@a3t/rapid-core 0.1.0 → 0.1.2
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 +171 -0
- package/dist/index.d.ts +94 -1
- package/dist/index.js +501 -64
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# @a3t/rapid-core
|
|
2
|
+
|
|
3
|
+
Core library for RAPID - AI-assisted development with dev containers.
|
|
4
|
+
|
|
5
|
+
This package provides the foundational utilities for orchestrating AI coding assistants within containerized development environments.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🐳 **Dev Container Management** - Control containerized environments via devcontainer CLI
|
|
10
|
+
- 🤖 **Agent Configuration** - Manage multiple AI coding assistants (Claude Code, OpenCode, Aider, etc.)
|
|
11
|
+
- 🔐 **Secret Management** - Integration with 1Password and Vault for credential handling
|
|
12
|
+
- 🔌 **MCP Server Support** - Model Context Protocol integration for external tools and APIs
|
|
13
|
+
- ⚙️ **Configuration Loading** - Smart configuration resolution with cosmiconfig
|
|
14
|
+
- 🔍 **External Auth Detection** - Detect credentials from external AI tools
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @a3t/rapid-core
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Loading Configuration
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { loadConfig } from '@a3t/rapid-core';
|
|
28
|
+
|
|
29
|
+
const { config, rootDir } = await loadConfig();
|
|
30
|
+
console.log(config.agents.default); // 'claude'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Managing Containers
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { getContainerStatus, startContainer, execInContainer } from '@a3t/rapid-core';
|
|
37
|
+
|
|
38
|
+
// Check if container is running
|
|
39
|
+
const status = await getContainerStatus(projectRoot, config);
|
|
40
|
+
|
|
41
|
+
// Start container
|
|
42
|
+
const result = await startContainer(projectRoot, config);
|
|
43
|
+
|
|
44
|
+
// Execute command in container
|
|
45
|
+
await execInContainer(projectRoot, ['claude'], config);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Agent Detection
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { checkAllAgents, getAgent, launchAgent } from '@a3t/rapid-core';
|
|
52
|
+
|
|
53
|
+
// Check installed agents
|
|
54
|
+
const agents = await checkAllAgents(config);
|
|
55
|
+
|
|
56
|
+
// Get specific agent
|
|
57
|
+
const claude = getAgent(config, 'claude');
|
|
58
|
+
|
|
59
|
+
// Launch agent
|
|
60
|
+
await launchAgent(claude, { cwd: projectRoot });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### External Authentication
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { detectClaudeCodeAuth, detectAllCredentials, getAuthStatus } from '@a3t/rapid-core';
|
|
67
|
+
|
|
68
|
+
// Detect Claude Code credentials
|
|
69
|
+
const claudeAuth = await detectClaudeCodeAuth();
|
|
70
|
+
|
|
71
|
+
// Detect all credentials from external tools
|
|
72
|
+
const credentials = await detectAllCredentials();
|
|
73
|
+
|
|
74
|
+
// Get authentication status
|
|
75
|
+
const authStatus = await getAuthStatus();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## API Reference
|
|
79
|
+
|
|
80
|
+
### Configuration
|
|
81
|
+
|
|
82
|
+
- `loadConfig(cwd?)` - Load RAPID configuration from cosmiconfig search
|
|
83
|
+
- `loadConfigFromFile(filepath)` - Load configuration from specific file
|
|
84
|
+
- `getDefaultConfig()` - Get default configuration
|
|
85
|
+
- `mergeWithDefaults(config)` - Merge user config with defaults
|
|
86
|
+
|
|
87
|
+
### Container Management
|
|
88
|
+
|
|
89
|
+
- `hasDevcontainerCli()` - Check if devcontainer CLI is installed
|
|
90
|
+
- `hasDocker()` - Check if Docker is available
|
|
91
|
+
- `getContainerStatus(rootDir, config)` - Get current container status
|
|
92
|
+
- `startContainer(rootDir, config, options)` - Start dev container
|
|
93
|
+
- `stopContainer(rootDir, config, options)` - Stop dev container
|
|
94
|
+
- `execInContainer(rootDir, command, config, options)` - Execute command in container
|
|
95
|
+
|
|
96
|
+
### Agent Management
|
|
97
|
+
|
|
98
|
+
- `checkAgentAvailable(agent)` - Check if agent CLI is installed
|
|
99
|
+
- `checkAllAgents(config)` - Check all configured agents
|
|
100
|
+
- `getDefaultAgent(config)` - Get default agent from config
|
|
101
|
+
- `getAgent(config, name)` - Get specific agent by name
|
|
102
|
+
- `launchAgent(agent, options)` - Launch agent CLI
|
|
103
|
+
|
|
104
|
+
### Authentication
|
|
105
|
+
|
|
106
|
+
- `detectClaudeCodeAuth()` - Detect Claude Code credentials
|
|
107
|
+
- `detectCodexAuth()` - Detect OpenAI Codex credentials
|
|
108
|
+
- `detectGeminiAuth()` - Detect Google Gemini credentials
|
|
109
|
+
- `detectAiderAuth()` - Detect Aider API keys
|
|
110
|
+
- `detectEnvAuth()` - Detect API keys from environment
|
|
111
|
+
- `detectAllCredentials(config)` - Detect all available credentials
|
|
112
|
+
- `getAuthStatus(config)` - Get authentication status summary
|
|
113
|
+
- `getCredentialsForProvider(provider, config)` - Get credentials for specific provider
|
|
114
|
+
- `getAuthEnvironment(config)` - Get environment variables for detected credentials
|
|
115
|
+
|
|
116
|
+
## Types
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import type {
|
|
120
|
+
RapidConfig,
|
|
121
|
+
ContainerConfig,
|
|
122
|
+
AgentsConfig,
|
|
123
|
+
AgentDefinition,
|
|
124
|
+
SecretsConfig,
|
|
125
|
+
ContextConfig,
|
|
126
|
+
McpConfig,
|
|
127
|
+
DetectedCredential,
|
|
128
|
+
AuthStatus,
|
|
129
|
+
} from '@a3t/rapid-core';
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Configuration File Format
|
|
133
|
+
|
|
134
|
+
See [rapid.json Specification](https://github.com/a3tai/rapid/docs/reference/rapid.json-spec.md) for complete configuration reference.
|
|
135
|
+
|
|
136
|
+
## Logger
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { logger, setLogLevel } from '@a3t/rapid-core';
|
|
140
|
+
|
|
141
|
+
// Set log level
|
|
142
|
+
setLogLevel('debug'); // 'debug' | 'info' | 'warn' | 'error'
|
|
143
|
+
|
|
144
|
+
// Log messages
|
|
145
|
+
logger.info('Information message');
|
|
146
|
+
logger.warn('Warning message');
|
|
147
|
+
logger.error('Error message');
|
|
148
|
+
logger.success('Success message');
|
|
149
|
+
logger.blank(); // Empty line
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Error Handling
|
|
153
|
+
|
|
154
|
+
Most async functions return success/error objects rather than throwing:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
const result = await startContainer(rootDir, config);
|
|
158
|
+
if (!result.success) {
|
|
159
|
+
console.error(result.error);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## See Also
|
|
164
|
+
|
|
165
|
+
- [@a3t/rapid](https://www.npmjs.com/package/@a3t/rapid) - CLI tool
|
|
166
|
+
- [@a3t/rapid-schema](https://www.npmjs.com/package/@a3t/rapid-schema) - JSON schema
|
|
167
|
+
- [RAPID Documentation](https://getrapid.dev)
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT © 2026 Rude Company LLC
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,18 @@ interface ContainerConfig {
|
|
|
17
17
|
autoStart?: boolean;
|
|
18
18
|
buildArgs?: Record<string, string>;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* External auth source types
|
|
22
|
+
*/
|
|
23
|
+
type ExternalAuthSource = 'claude-code' | 'codex' | 'gemini-cli' | 'aider' | 'env';
|
|
24
|
+
/**
|
|
25
|
+
* External auth configuration
|
|
26
|
+
*/
|
|
27
|
+
interface ExternalAuthConfig {
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
sources?: ExternalAuthSource[];
|
|
30
|
+
preferSource?: ExternalAuthSource;
|
|
31
|
+
}
|
|
20
32
|
interface SecretsConfig {
|
|
21
33
|
provider?: 'env' | '1password' | 'vault';
|
|
22
34
|
vault?: string;
|
|
@@ -24,6 +36,7 @@ interface SecretsConfig {
|
|
|
24
36
|
items?: Record<string, string>;
|
|
25
37
|
envrc?: EnvrcConfig;
|
|
26
38
|
dotenv?: DotenvConfig;
|
|
39
|
+
externalAuth?: ExternalAuthConfig;
|
|
27
40
|
}
|
|
28
41
|
interface EnvrcConfig {
|
|
29
42
|
generate?: boolean;
|
|
@@ -81,6 +94,32 @@ interface EnvironmentStatus {
|
|
|
81
94
|
secretsLoaded: boolean;
|
|
82
95
|
containerRunning: boolean;
|
|
83
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Detected credential from an external tool
|
|
99
|
+
*/
|
|
100
|
+
interface DetectedCredential {
|
|
101
|
+
source: ExternalAuthSource;
|
|
102
|
+
provider: 'anthropic' | 'openai' | 'google' | 'unknown';
|
|
103
|
+
authType: 'api-key' | 'oauth' | 'service-account';
|
|
104
|
+
envVar?: string;
|
|
105
|
+
value?: string;
|
|
106
|
+
expiresAt?: Date;
|
|
107
|
+
accountInfo?: {
|
|
108
|
+
email?: string;
|
|
109
|
+
organization?: string;
|
|
110
|
+
plan?: string;
|
|
111
|
+
};
|
|
112
|
+
configPath?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Auth status summary
|
|
116
|
+
*/
|
|
117
|
+
interface AuthStatus {
|
|
118
|
+
authenticated: boolean;
|
|
119
|
+
sources: DetectedCredential[];
|
|
120
|
+
preferredSource?: DetectedCredential;
|
|
121
|
+
warnings?: string[];
|
|
122
|
+
}
|
|
84
123
|
|
|
85
124
|
/**
|
|
86
125
|
* Configuration loading and validation
|
|
@@ -135,6 +174,8 @@ declare function launchAgent(agent: AgentDefinition, options?: {
|
|
|
135
174
|
cwd?: string;
|
|
136
175
|
env?: Record<string, string>;
|
|
137
176
|
stdio?: 'inherit' | 'pipe';
|
|
177
|
+
useExternalAuth?: boolean;
|
|
178
|
+
externalAuthConfig?: ExternalAuthConfig;
|
|
138
179
|
}): Promise<void>;
|
|
139
180
|
|
|
140
181
|
/**
|
|
@@ -327,4 +368,56 @@ declare function getProviderInfo(provider: 'env' | '1password' | 'vault'): {
|
|
|
327
368
|
installUrl: string | null;
|
|
328
369
|
};
|
|
329
370
|
|
|
330
|
-
|
|
371
|
+
/**
|
|
372
|
+
* External Authentication Detection
|
|
373
|
+
*
|
|
374
|
+
* Detects and reuses credentials from AI coding tools like:
|
|
375
|
+
* - Claude Code (~/.claude.json)
|
|
376
|
+
* - OpenAI Codex (~/.codex/auth.json)
|
|
377
|
+
* - Gemini CLI (~/.gemini/)
|
|
378
|
+
* - Aider (.env files with API keys)
|
|
379
|
+
*/
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Detect Claude Code credentials from ~/.claude.json
|
|
383
|
+
*/
|
|
384
|
+
declare function detectClaudeCodeAuth(): Promise<DetectedCredential | null>;
|
|
385
|
+
/**
|
|
386
|
+
* Detect OpenAI Codex credentials from ~/.codex/auth.json
|
|
387
|
+
*/
|
|
388
|
+
declare function detectCodexAuth(): Promise<DetectedCredential | null>;
|
|
389
|
+
/**
|
|
390
|
+
* Detect Gemini CLI credentials from ~/.gemini/
|
|
391
|
+
*/
|
|
392
|
+
declare function detectGeminiAuth(): Promise<DetectedCredential | null>;
|
|
393
|
+
/**
|
|
394
|
+
* Detect Aider credentials from environment variables
|
|
395
|
+
* Aider uses standard environment variables, no config file
|
|
396
|
+
*/
|
|
397
|
+
declare function detectAiderAuth(): Promise<DetectedCredential[]>;
|
|
398
|
+
/**
|
|
399
|
+
* Detect credentials from standard environment variables
|
|
400
|
+
*/
|
|
401
|
+
declare function detectEnvAuth(): Promise<DetectedCredential[]>;
|
|
402
|
+
/**
|
|
403
|
+
* Detect all available credentials from external sources
|
|
404
|
+
*/
|
|
405
|
+
declare function detectAllCredentials(config?: ExternalAuthConfig): Promise<DetectedCredential[]>;
|
|
406
|
+
/**
|
|
407
|
+
* Get authentication status summary
|
|
408
|
+
*/
|
|
409
|
+
declare function getAuthStatus(config?: ExternalAuthConfig): Promise<AuthStatus>;
|
|
410
|
+
/**
|
|
411
|
+
* Get credentials for a specific provider
|
|
412
|
+
*/
|
|
413
|
+
declare function getCredentialsForProvider(provider: 'anthropic' | 'openai' | 'google', config?: ExternalAuthConfig): Promise<DetectedCredential | null>;
|
|
414
|
+
/**
|
|
415
|
+
* Get environment variables to inject based on detected credentials
|
|
416
|
+
*/
|
|
417
|
+
declare function getAuthEnvironment(config?: ExternalAuthConfig): Promise<Record<string, string>>;
|
|
418
|
+
/**
|
|
419
|
+
* Format auth status for display
|
|
420
|
+
*/
|
|
421
|
+
declare function formatAuthStatus(status: AuthStatus): string;
|
|
422
|
+
|
|
423
|
+
export { type AgentDefinition, type AgentStatus, type AgentsConfig, type AuthStatus, type ContainerConfig, type ContainerStatus, type ContextConfig, type DetectedCredential, type DevcontainerConfig, type DotenvConfig, type EnvironmentStatus, type EnvrcConfig, type ExternalAuthConfig, type ExternalAuthSource, type LoadedConfig, type LogLevel, type McpConfig, type McpServerConfig, type OpAuthStatus, type RapidConfig, type SecretStatus, type SecretsConfig, type SecretsStatus, checkAgentAvailable, checkAllAgents, detectAiderAuth, detectAllCredentials, detectClaudeCodeAuth, detectCodexAuth, detectEnvAuth, detectGeminiAuth, execInContainer, formatAuthStatus, generateEnvrc, getAgent, getAuthEnvironment, getAuthStatus, getContainerName, getContainerStatus, getCredentialsForProvider, getDefaultAgent, getDefaultConfig, getDevcontainerPath, getLogLevel, getOpAuthStatus, getProviderInfo, hasDevcontainerCli, hasDocker, hasEnvrc, hasOpCli, hasOpServiceAccountToken, hasVaultCli, isOpAuthenticated, isVaultAuthenticated, launchAgent, loadConfig, loadConfigFromFile, loadDevcontainerConfig, loadSecrets, logger, mergeWithDefaults, readEnvrc, readOpSecret, readVaultSecret, setLogLevel, startContainer, stopContainer, verifySecret, verifySecrets, writeEnvrc };
|
package/dist/index.js
CHANGED
|
@@ -94,58 +94,11 @@ function mergeWithDefaults(config) {
|
|
|
94
94
|
// src/agents.ts
|
|
95
95
|
import { execa } from "execa";
|
|
96
96
|
import which from "which";
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const result = await execa(agent.cli, ["--version"], { timeout: 5e3 });
|
|
103
|
-
version = result.stdout.trim().split("\n")[0];
|
|
104
|
-
} catch {
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
name: agent.cli,
|
|
108
|
-
available: true,
|
|
109
|
-
cliPath,
|
|
110
|
-
...version !== void 0 && { version }
|
|
111
|
-
};
|
|
112
|
-
} catch {
|
|
113
|
-
return {
|
|
114
|
-
name: agent.cli,
|
|
115
|
-
available: false
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
async function checkAllAgents(config) {
|
|
120
|
-
const results = [];
|
|
121
|
-
for (const [name, agent] of Object.entries(config.agents.available)) {
|
|
122
|
-
const status = await checkAgentAvailable(agent);
|
|
123
|
-
results.push({
|
|
124
|
-
...status,
|
|
125
|
-
name
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
return results;
|
|
129
|
-
}
|
|
130
|
-
function getDefaultAgent(config) {
|
|
131
|
-
const defaultName = config.agents.default;
|
|
132
|
-
return config.agents.available[defaultName] || null;
|
|
133
|
-
}
|
|
134
|
-
function getAgent(config, name) {
|
|
135
|
-
return config.agents.available[name] || null;
|
|
136
|
-
}
|
|
137
|
-
async function launchAgent(agent, options = {}) {
|
|
138
|
-
const args = agent.args ?? [];
|
|
139
|
-
const cwd = options.cwd ?? process.cwd();
|
|
140
|
-
await execa(agent.cli, args, {
|
|
141
|
-
cwd,
|
|
142
|
-
env: {
|
|
143
|
-
...process.env,
|
|
144
|
-
...options.env
|
|
145
|
-
},
|
|
146
|
-
stdio: options.stdio ?? "inherit"
|
|
147
|
-
});
|
|
148
|
-
}
|
|
97
|
+
|
|
98
|
+
// src/external-auth.ts
|
|
99
|
+
import { readFile as readFile2, access } from "fs/promises";
|
|
100
|
+
import { homedir } from "os";
|
|
101
|
+
import { join } from "path";
|
|
149
102
|
|
|
150
103
|
// src/logger.ts
|
|
151
104
|
import chalk from "chalk";
|
|
@@ -213,11 +166,485 @@ var logger = {
|
|
|
213
166
|
}
|
|
214
167
|
};
|
|
215
168
|
|
|
169
|
+
// src/external-auth.ts
|
|
170
|
+
var DEFAULT_CONFIG = {
|
|
171
|
+
enabled: true,
|
|
172
|
+
sources: ["claude-code", "codex", "gemini-cli", "aider", "env"]
|
|
173
|
+
};
|
|
174
|
+
async function fileExists(path) {
|
|
175
|
+
try {
|
|
176
|
+
await access(path);
|
|
177
|
+
return true;
|
|
178
|
+
} catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function readJsonFile(path) {
|
|
183
|
+
try {
|
|
184
|
+
const content = await readFile2(path, "utf-8");
|
|
185
|
+
return JSON.parse(content);
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function detectClaudeCodeAuth() {
|
|
191
|
+
const home = homedir();
|
|
192
|
+
const configPath = join(home, ".claude.json");
|
|
193
|
+
if (!await fileExists(configPath)) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const config = await readJsonFile(configPath);
|
|
197
|
+
if (!config) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const oauth = config.oauthAccount || config.claudeAiOauth;
|
|
201
|
+
if (oauth?.accessToken) {
|
|
202
|
+
const expiresAt = oauth.expiresAt ? new Date(oauth.expiresAt) : void 0;
|
|
203
|
+
if (expiresAt && expiresAt < /* @__PURE__ */ new Date()) {
|
|
204
|
+
logger.debug("Claude Code OAuth token expired");
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const cred = {
|
|
208
|
+
source: "claude-code",
|
|
209
|
+
provider: "anthropic",
|
|
210
|
+
authType: "oauth",
|
|
211
|
+
value: oauth.accessToken,
|
|
212
|
+
configPath
|
|
213
|
+
};
|
|
214
|
+
if (expiresAt) {
|
|
215
|
+
cred.expiresAt = expiresAt;
|
|
216
|
+
}
|
|
217
|
+
const accountInfo = {};
|
|
218
|
+
if (config.oauthAccount?.emailAddress) {
|
|
219
|
+
accountInfo.email = config.oauthAccount.emailAddress;
|
|
220
|
+
}
|
|
221
|
+
if (config.oauthAccount?.organizationName) {
|
|
222
|
+
accountInfo.organization = config.oauthAccount.organizationName;
|
|
223
|
+
}
|
|
224
|
+
if (config.oauthAccount?.planType) {
|
|
225
|
+
accountInfo.plan = config.oauthAccount.planType;
|
|
226
|
+
}
|
|
227
|
+
if (Object.keys(accountInfo).length > 0) {
|
|
228
|
+
cred.accountInfo = accountInfo;
|
|
229
|
+
}
|
|
230
|
+
return cred;
|
|
231
|
+
}
|
|
232
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
233
|
+
if (apiKey) {
|
|
234
|
+
return {
|
|
235
|
+
source: "claude-code",
|
|
236
|
+
provider: "anthropic",
|
|
237
|
+
authType: "api-key",
|
|
238
|
+
envVar: "ANTHROPIC_API_KEY",
|
|
239
|
+
value: apiKey,
|
|
240
|
+
configPath
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
async function detectCodexAuth() {
|
|
246
|
+
const home = homedir();
|
|
247
|
+
const configPath = join(home, ".codex", "auth.json");
|
|
248
|
+
if (!await fileExists(configPath)) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
const config = await readJsonFile(configPath);
|
|
252
|
+
if (!config) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
if (config.chatgpt?.accessToken) {
|
|
256
|
+
const expiresAt = config.chatgpt.expiresAt ? new Date(config.chatgpt.expiresAt) : void 0;
|
|
257
|
+
if (expiresAt && expiresAt < /* @__PURE__ */ new Date()) {
|
|
258
|
+
logger.debug("Codex ChatGPT OAuth token expired");
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const cred = {
|
|
262
|
+
source: "codex",
|
|
263
|
+
provider: "openai",
|
|
264
|
+
authType: "oauth",
|
|
265
|
+
value: config.chatgpt.accessToken,
|
|
266
|
+
configPath
|
|
267
|
+
};
|
|
268
|
+
if (expiresAt) {
|
|
269
|
+
cred.expiresAt = expiresAt;
|
|
270
|
+
}
|
|
271
|
+
const accountInfo = {};
|
|
272
|
+
if (config.chatgpt.email) {
|
|
273
|
+
accountInfo.email = config.chatgpt.email;
|
|
274
|
+
}
|
|
275
|
+
if (config.chatgpt.workspaceId) {
|
|
276
|
+
accountInfo.organization = config.chatgpt.workspaceId;
|
|
277
|
+
}
|
|
278
|
+
if (Object.keys(accountInfo).length > 0) {
|
|
279
|
+
cred.accountInfo = accountInfo;
|
|
280
|
+
}
|
|
281
|
+
return cred;
|
|
282
|
+
}
|
|
283
|
+
if (config.api?.apiKey) {
|
|
284
|
+
return {
|
|
285
|
+
source: "codex",
|
|
286
|
+
provider: "openai",
|
|
287
|
+
authType: "api-key",
|
|
288
|
+
value: config.api.apiKey,
|
|
289
|
+
configPath
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
293
|
+
if (apiKey) {
|
|
294
|
+
return {
|
|
295
|
+
source: "codex",
|
|
296
|
+
provider: "openai",
|
|
297
|
+
authType: "api-key",
|
|
298
|
+
envVar: "OPENAI_API_KEY",
|
|
299
|
+
value: apiKey
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
async function detectGeminiAuth() {
|
|
305
|
+
const home = homedir();
|
|
306
|
+
const settingsPath = join(home, ".gemini", "settings.json");
|
|
307
|
+
if (await fileExists(settingsPath)) {
|
|
308
|
+
const settings = await readJsonFile(settingsPath);
|
|
309
|
+
if (settings?.auth?.oauth?.accessToken) {
|
|
310
|
+
const oauth = settings.auth.oauth;
|
|
311
|
+
const expiresAt = oauth.expiresAt ? new Date(oauth.expiresAt) : void 0;
|
|
312
|
+
if (expiresAt && expiresAt < /* @__PURE__ */ new Date()) {
|
|
313
|
+
logger.debug("Gemini CLI OAuth token expired");
|
|
314
|
+
} else {
|
|
315
|
+
const cred = {
|
|
316
|
+
source: "gemini-cli",
|
|
317
|
+
provider: "google",
|
|
318
|
+
authType: "oauth",
|
|
319
|
+
value: oauth.accessToken,
|
|
320
|
+
configPath: settingsPath
|
|
321
|
+
};
|
|
322
|
+
if (expiresAt) {
|
|
323
|
+
cred.expiresAt = expiresAt;
|
|
324
|
+
}
|
|
325
|
+
const accountInfo = {};
|
|
326
|
+
if (oauth.email) {
|
|
327
|
+
accountInfo.email = oauth.email;
|
|
328
|
+
}
|
|
329
|
+
if (settings.googleCloudProject) {
|
|
330
|
+
accountInfo.organization = settings.googleCloudProject;
|
|
331
|
+
}
|
|
332
|
+
if (Object.keys(accountInfo).length > 0) {
|
|
333
|
+
cred.accountInfo = accountInfo;
|
|
334
|
+
}
|
|
335
|
+
return cred;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const geminiKey = process.env.GEMINI_API_KEY;
|
|
340
|
+
if (geminiKey) {
|
|
341
|
+
return {
|
|
342
|
+
source: "gemini-cli",
|
|
343
|
+
provider: "google",
|
|
344
|
+
authType: "api-key",
|
|
345
|
+
envVar: "GEMINI_API_KEY",
|
|
346
|
+
value: geminiKey
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
const googleKey = process.env.GOOGLE_API_KEY;
|
|
350
|
+
if (googleKey) {
|
|
351
|
+
return {
|
|
352
|
+
source: "gemini-cli",
|
|
353
|
+
provider: "google",
|
|
354
|
+
authType: "api-key",
|
|
355
|
+
envVar: "GOOGLE_API_KEY",
|
|
356
|
+
value: googleKey
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
async function detectAiderAuth() {
|
|
362
|
+
const credentials = [];
|
|
363
|
+
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
364
|
+
if (anthropicKey) {
|
|
365
|
+
credentials.push({
|
|
366
|
+
source: "aider",
|
|
367
|
+
provider: "anthropic",
|
|
368
|
+
authType: "api-key",
|
|
369
|
+
envVar: "ANTHROPIC_API_KEY",
|
|
370
|
+
value: anthropicKey
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
const openaiKey = process.env.OPENAI_API_KEY;
|
|
374
|
+
if (openaiKey) {
|
|
375
|
+
credentials.push({
|
|
376
|
+
source: "aider",
|
|
377
|
+
provider: "openai",
|
|
378
|
+
authType: "api-key",
|
|
379
|
+
envVar: "OPENAI_API_KEY",
|
|
380
|
+
value: openaiKey
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
const geminiKey = process.env.GEMINI_API_KEY;
|
|
384
|
+
if (geminiKey) {
|
|
385
|
+
credentials.push({
|
|
386
|
+
source: "aider",
|
|
387
|
+
provider: "google",
|
|
388
|
+
authType: "api-key",
|
|
389
|
+
envVar: "GEMINI_API_KEY",
|
|
390
|
+
value: geminiKey
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return credentials;
|
|
394
|
+
}
|
|
395
|
+
async function detectEnvAuth() {
|
|
396
|
+
const credentials = [];
|
|
397
|
+
const envMappings = [
|
|
398
|
+
{ envVar: "ANTHROPIC_API_KEY", provider: "anthropic" },
|
|
399
|
+
{ envVar: "OPENAI_API_KEY", provider: "openai" },
|
|
400
|
+
{ envVar: "GEMINI_API_KEY", provider: "google" },
|
|
401
|
+
{ envVar: "GOOGLE_API_KEY", provider: "google" }
|
|
402
|
+
];
|
|
403
|
+
for (const { envVar, provider } of envMappings) {
|
|
404
|
+
const value = process.env[envVar];
|
|
405
|
+
if (value) {
|
|
406
|
+
credentials.push({
|
|
407
|
+
source: "env",
|
|
408
|
+
provider,
|
|
409
|
+
authType: "api-key",
|
|
410
|
+
envVar,
|
|
411
|
+
value
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return credentials;
|
|
416
|
+
}
|
|
417
|
+
async function detectAllCredentials(config = DEFAULT_CONFIG) {
|
|
418
|
+
if (!config.enabled) {
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
const sources = config.sources || DEFAULT_CONFIG.sources;
|
|
422
|
+
const credentials = [];
|
|
423
|
+
const seenValues = /* @__PURE__ */ new Set();
|
|
424
|
+
for (const source of sources) {
|
|
425
|
+
try {
|
|
426
|
+
let detected = null;
|
|
427
|
+
switch (source) {
|
|
428
|
+
case "claude-code":
|
|
429
|
+
detected = await detectClaudeCodeAuth();
|
|
430
|
+
break;
|
|
431
|
+
case "codex":
|
|
432
|
+
detected = await detectCodexAuth();
|
|
433
|
+
break;
|
|
434
|
+
case "gemini-cli":
|
|
435
|
+
detected = await detectGeminiAuth();
|
|
436
|
+
break;
|
|
437
|
+
case "aider":
|
|
438
|
+
detected = await detectAiderAuth();
|
|
439
|
+
break;
|
|
440
|
+
case "env":
|
|
441
|
+
detected = await detectEnvAuth();
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
if (detected) {
|
|
445
|
+
const items = Array.isArray(detected) ? detected : [detected];
|
|
446
|
+
for (const item of items) {
|
|
447
|
+
const key = item.value || item.envVar || "";
|
|
448
|
+
if (key && !seenValues.has(key)) {
|
|
449
|
+
seenValues.add(key);
|
|
450
|
+
credentials.push(item);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} catch (error) {
|
|
455
|
+
logger.debug(`Error detecting ${source} credentials:`, error);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return credentials;
|
|
459
|
+
}
|
|
460
|
+
async function getAuthStatus(config = DEFAULT_CONFIG) {
|
|
461
|
+
const credentials = await detectAllCredentials(config);
|
|
462
|
+
const warnings = [];
|
|
463
|
+
for (const cred of credentials) {
|
|
464
|
+
if (cred.expiresAt && cred.expiresAt < /* @__PURE__ */ new Date()) {
|
|
465
|
+
warnings.push(`${cred.source} OAuth token has expired. Please re-authenticate.`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
let preferredSource;
|
|
469
|
+
if (config.preferSource) {
|
|
470
|
+
preferredSource = credentials.find((c) => c.source === config.preferSource);
|
|
471
|
+
}
|
|
472
|
+
if (!preferredSource && credentials.length > 0) {
|
|
473
|
+
preferredSource = credentials.find((c) => c.authType === "oauth") || credentials[0];
|
|
474
|
+
}
|
|
475
|
+
const result = {
|
|
476
|
+
authenticated: credentials.length > 0,
|
|
477
|
+
sources: credentials
|
|
478
|
+
};
|
|
479
|
+
if (preferredSource) {
|
|
480
|
+
result.preferredSource = preferredSource;
|
|
481
|
+
}
|
|
482
|
+
if (warnings.length > 0) {
|
|
483
|
+
result.warnings = warnings;
|
|
484
|
+
}
|
|
485
|
+
return result;
|
|
486
|
+
}
|
|
487
|
+
async function getCredentialsForProvider(provider, config = DEFAULT_CONFIG) {
|
|
488
|
+
const credentials = await detectAllCredentials(config);
|
|
489
|
+
const providerCreds = credentials.filter((c) => c.provider === provider);
|
|
490
|
+
if (providerCreds.length === 0) {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
const found = providerCreds.find((c) => c.authType === "oauth");
|
|
494
|
+
return found || providerCreds[0] || null;
|
|
495
|
+
}
|
|
496
|
+
async function getAuthEnvironment(config = DEFAULT_CONFIG) {
|
|
497
|
+
const credentials = await detectAllCredentials(config);
|
|
498
|
+
const env = {};
|
|
499
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
500
|
+
for (const cred of credentials) {
|
|
501
|
+
const existing = byProvider.get(cred.provider);
|
|
502
|
+
if (!existing || cred.authType === "oauth" && existing.authType !== "oauth") {
|
|
503
|
+
byProvider.set(cred.provider, cred);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
for (const [provider, cred] of byProvider) {
|
|
507
|
+
if (!cred.value) continue;
|
|
508
|
+
switch (provider) {
|
|
509
|
+
case "anthropic":
|
|
510
|
+
if (cred.authType === "oauth") {
|
|
511
|
+
env["ANTHROPIC_AUTH_TOKEN"] = cred.value;
|
|
512
|
+
} else {
|
|
513
|
+
env["ANTHROPIC_API_KEY"] = cred.value;
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
case "openai":
|
|
517
|
+
if (cred.authType === "oauth") {
|
|
518
|
+
env["OPENAI_AUTH_TOKEN"] = cred.value;
|
|
519
|
+
} else {
|
|
520
|
+
env["OPENAI_API_KEY"] = cred.value;
|
|
521
|
+
}
|
|
522
|
+
break;
|
|
523
|
+
case "google":
|
|
524
|
+
if (cred.authType === "oauth") {
|
|
525
|
+
env["GOOGLE_AUTH_TOKEN"] = cred.value;
|
|
526
|
+
} else {
|
|
527
|
+
if (cred.envVar === "GOOGLE_API_KEY") {
|
|
528
|
+
env["GOOGLE_API_KEY"] = cred.value;
|
|
529
|
+
} else {
|
|
530
|
+
env["GEMINI_API_KEY"] = cred.value;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return env;
|
|
537
|
+
}
|
|
538
|
+
function formatAuthStatus(status) {
|
|
539
|
+
const lines = [];
|
|
540
|
+
if (!status.authenticated) {
|
|
541
|
+
lines.push("No authentication detected");
|
|
542
|
+
lines.push("");
|
|
543
|
+
lines.push("To authenticate, either:");
|
|
544
|
+
lines.push(" - Log in with Claude Code: claude");
|
|
545
|
+
lines.push(" - Log in with Codex: codex");
|
|
546
|
+
lines.push(" - Log in with Gemini CLI: gemini");
|
|
547
|
+
lines.push(" - Set environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.)");
|
|
548
|
+
return lines.join("\n");
|
|
549
|
+
}
|
|
550
|
+
lines.push("Detected authentication sources:");
|
|
551
|
+
lines.push("");
|
|
552
|
+
for (const cred of status.sources) {
|
|
553
|
+
const isPrimary = cred === status.preferredSource;
|
|
554
|
+
const prefix = isPrimary ? "* " : " ";
|
|
555
|
+
const authType = cred.authType === "oauth" ? "OAuth" : "API Key";
|
|
556
|
+
let line = `${prefix}${cred.source} (${cred.provider}, ${authType})`;
|
|
557
|
+
if (cred.accountInfo?.email) {
|
|
558
|
+
line += ` - ${cred.accountInfo.email}`;
|
|
559
|
+
}
|
|
560
|
+
if (cred.accountInfo?.plan) {
|
|
561
|
+
line += ` [${cred.accountInfo.plan}]`;
|
|
562
|
+
}
|
|
563
|
+
if (cred.expiresAt) {
|
|
564
|
+
const expiresIn = Math.round((cred.expiresAt.getTime() - Date.now()) / 1e3 / 60);
|
|
565
|
+
if (expiresIn > 0) {
|
|
566
|
+
line += ` (expires in ${expiresIn}m)`;
|
|
567
|
+
} else {
|
|
568
|
+
line += " (EXPIRED)";
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
lines.push(line);
|
|
572
|
+
}
|
|
573
|
+
if (status.warnings && status.warnings.length > 0) {
|
|
574
|
+
lines.push("");
|
|
575
|
+
lines.push("Warnings:");
|
|
576
|
+
for (const warning of status.warnings) {
|
|
577
|
+
lines.push(` ! ${warning}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return lines.join("\n");
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/agents.ts
|
|
584
|
+
async function checkAgentAvailable(agent) {
|
|
585
|
+
try {
|
|
586
|
+
const cliPath = await which(agent.cli);
|
|
587
|
+
let version;
|
|
588
|
+
try {
|
|
589
|
+
const result = await execa(agent.cli, ["--version"], { timeout: 5e3 });
|
|
590
|
+
version = result.stdout.trim().split("\n")[0];
|
|
591
|
+
} catch {
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
name: agent.cli,
|
|
595
|
+
available: true,
|
|
596
|
+
cliPath,
|
|
597
|
+
...version !== void 0 && { version }
|
|
598
|
+
};
|
|
599
|
+
} catch {
|
|
600
|
+
return {
|
|
601
|
+
name: agent.cli,
|
|
602
|
+
available: false
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
async function checkAllAgents(config) {
|
|
607
|
+
const results = [];
|
|
608
|
+
for (const [name, agent] of Object.entries(config.agents.available)) {
|
|
609
|
+
const status = await checkAgentAvailable(agent);
|
|
610
|
+
results.push({
|
|
611
|
+
...status,
|
|
612
|
+
name
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
return results;
|
|
616
|
+
}
|
|
617
|
+
function getDefaultAgent(config) {
|
|
618
|
+
const defaultName = config.agents.default;
|
|
619
|
+
return config.agents.available[defaultName] || null;
|
|
620
|
+
}
|
|
621
|
+
function getAgent(config, name) {
|
|
622
|
+
return config.agents.available[name] || null;
|
|
623
|
+
}
|
|
624
|
+
async function launchAgent(agent, options = {}) {
|
|
625
|
+
const args = agent.args ?? [];
|
|
626
|
+
const cwd = options.cwd ?? process.cwd();
|
|
627
|
+
let authEnv = {};
|
|
628
|
+
if (options.useExternalAuth !== false) {
|
|
629
|
+
authEnv = await getAuthEnvironment(options.externalAuthConfig);
|
|
630
|
+
}
|
|
631
|
+
await execa(agent.cli, args, {
|
|
632
|
+
cwd,
|
|
633
|
+
env: {
|
|
634
|
+
...process.env,
|
|
635
|
+
...authEnv,
|
|
636
|
+
...options.env
|
|
637
|
+
// User-provided env takes precedence
|
|
638
|
+
},
|
|
639
|
+
stdio: options.stdio ?? "inherit"
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
|
|
216
643
|
// src/container.ts
|
|
217
644
|
import { execa as execa2 } from "execa";
|
|
218
645
|
import which2 from "which";
|
|
219
|
-
import { readFile as
|
|
220
|
-
import { join } from "path";
|
|
646
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
647
|
+
import { join as join2 } from "path";
|
|
221
648
|
async function hasDevcontainerCli() {
|
|
222
649
|
try {
|
|
223
650
|
await which2("devcontainer");
|
|
@@ -237,14 +664,14 @@ async function hasDocker() {
|
|
|
237
664
|
function getDevcontainerPath(rootDir, config) {
|
|
238
665
|
const customPath = config?.container?.devcontainer;
|
|
239
666
|
if (customPath) {
|
|
240
|
-
return
|
|
667
|
+
return join2(rootDir, customPath);
|
|
241
668
|
}
|
|
242
|
-
return
|
|
669
|
+
return join2(rootDir, ".devcontainer", "devcontainer.json");
|
|
243
670
|
}
|
|
244
671
|
async function loadDevcontainerConfig(rootDir, config) {
|
|
245
672
|
try {
|
|
246
673
|
const configPath = getDevcontainerPath(rootDir, config);
|
|
247
|
-
const content = await
|
|
674
|
+
const content = await readFile3(configPath, "utf-8");
|
|
248
675
|
return JSON.parse(content);
|
|
249
676
|
} catch {
|
|
250
677
|
return null;
|
|
@@ -370,8 +797,8 @@ async function execInContainer(rootDir, command, _config, options = {}) {
|
|
|
370
797
|
|
|
371
798
|
// src/secrets.ts
|
|
372
799
|
import { spawn } from "child_process";
|
|
373
|
-
import { readFile as
|
|
374
|
-
import { join as
|
|
800
|
+
import { readFile as readFile4, writeFile, access as access2 } from "fs/promises";
|
|
801
|
+
import { join as join3 } from "path";
|
|
375
802
|
async function execCommand(command, args, options = {}) {
|
|
376
803
|
return new Promise((resolve2) => {
|
|
377
804
|
const proc = spawn(command, args, {
|
|
@@ -629,16 +1056,16 @@ function generateEnvrc(config) {
|
|
|
629
1056
|
}
|
|
630
1057
|
async function writeEnvrc(rootDir, config) {
|
|
631
1058
|
const envrcPath = config.envrc?.path || ".envrc";
|
|
632
|
-
const fullPath =
|
|
1059
|
+
const fullPath = join3(rootDir, envrcPath);
|
|
633
1060
|
const content = generateEnvrc(config);
|
|
634
1061
|
await writeFile(fullPath, content);
|
|
635
1062
|
return fullPath;
|
|
636
1063
|
}
|
|
637
1064
|
async function hasEnvrc(rootDir, config) {
|
|
638
1065
|
const envrcPath = config?.envrc?.path || ".envrc";
|
|
639
|
-
const fullPath =
|
|
1066
|
+
const fullPath = join3(rootDir, envrcPath);
|
|
640
1067
|
try {
|
|
641
|
-
await
|
|
1068
|
+
await access2(fullPath);
|
|
642
1069
|
return true;
|
|
643
1070
|
} catch {
|
|
644
1071
|
return false;
|
|
@@ -646,9 +1073,9 @@ async function hasEnvrc(rootDir, config) {
|
|
|
646
1073
|
}
|
|
647
1074
|
async function readEnvrc(rootDir, config) {
|
|
648
1075
|
const envrcPath = config?.envrc?.path || ".envrc";
|
|
649
|
-
const fullPath =
|
|
1076
|
+
const fullPath = join3(rootDir, envrcPath);
|
|
650
1077
|
try {
|
|
651
|
-
const content = await
|
|
1078
|
+
const content = await readFile4(fullPath, "utf-8");
|
|
652
1079
|
return content;
|
|
653
1080
|
} catch {
|
|
654
1081
|
return null;
|
|
@@ -682,11 +1109,21 @@ function getProviderInfo(provider) {
|
|
|
682
1109
|
export {
|
|
683
1110
|
checkAgentAvailable,
|
|
684
1111
|
checkAllAgents,
|
|
1112
|
+
detectAiderAuth,
|
|
1113
|
+
detectAllCredentials,
|
|
1114
|
+
detectClaudeCodeAuth,
|
|
1115
|
+
detectCodexAuth,
|
|
1116
|
+
detectEnvAuth,
|
|
1117
|
+
detectGeminiAuth,
|
|
685
1118
|
execInContainer,
|
|
1119
|
+
formatAuthStatus,
|
|
686
1120
|
generateEnvrc,
|
|
687
1121
|
getAgent,
|
|
1122
|
+
getAuthEnvironment,
|
|
1123
|
+
getAuthStatus,
|
|
688
1124
|
getContainerName,
|
|
689
1125
|
getContainerStatus,
|
|
1126
|
+
getCredentialsForProvider,
|
|
690
1127
|
getDefaultAgent,
|
|
691
1128
|
getDefaultConfig,
|
|
692
1129
|
getDevcontainerPath,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/agents.ts","../src/logger.ts","../src/container.ts","../src/secrets.ts"],"sourcesContent":["/**\n * Configuration loading and validation\n */\n\nimport { cosmiconfig } from 'cosmiconfig';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport type { RapidConfig } from './types.js';\n\nconst CONFIG_NAME = 'rapid';\nconst CONFIG_FILES = ['rapid.json', 'rapid.config.json', '.rapidrc', '.rapidrc.json'];\n\nexport interface LoadedConfig {\n config: RapidConfig;\n filepath: string;\n rootDir: string;\n}\n\n/**\n * Load RAPID configuration from the current directory or ancestors\n */\nexport async function loadConfig(cwd?: string): Promise<LoadedConfig | null> {\n const explorer = cosmiconfig(CONFIG_NAME, {\n searchPlaces: CONFIG_FILES,\n loaders: {\n '.json': async (filepath) => {\n const content = await readFile(filepath, 'utf-8');\n return JSON.parse(content);\n },\n },\n });\n\n const result = await explorer.search(cwd);\n\n if (!result || result.isEmpty) {\n return null;\n }\n\n return {\n config: result.config as RapidConfig,\n filepath: result.filepath,\n rootDir: dirname(result.filepath),\n };\n}\n\n/**\n * Load configuration from a specific file\n */\nexport async function loadConfigFromFile(filepath: string): Promise<LoadedConfig> {\n const content = await readFile(filepath, 'utf-8');\n const config = JSON.parse(content) as RapidConfig;\n\n return {\n config,\n filepath: resolve(filepath),\n rootDir: dirname(resolve(filepath)),\n };\n}\n\n/**\n * Get default configuration\n */\nexport function getDefaultConfig(): RapidConfig {\n return {\n version: '1.0',\n agents: {\n default: 'claude',\n available: {\n claude: {\n cli: 'claude',\n instructionFile: 'CLAUDE.md',\n envVars: ['ANTHROPIC_API_KEY'],\n },\n opencode: {\n cli: 'opencode',\n instructionFile: 'AGENTS.md',\n envVars: ['ANTHROPIC_API_KEY'],\n },\n aider: {\n cli: 'aider',\n instructionFile: 'AGENTS.md',\n envVars: ['ANTHROPIC_API_KEY'],\n args: ['--model', 'claude-3-5-sonnet-20241022'],\n },\n },\n },\n secrets: {\n provider: 'env',\n },\n context: {\n files: ['README.md'],\n dirs: ['docs/'],\n generateAgentFiles: true,\n },\n };\n}\n\n/**\n * Merge user config with defaults\n */\nexport function mergeWithDefaults(config: Partial<RapidConfig>): RapidConfig {\n const defaults = getDefaultConfig();\n\n return {\n ...defaults,\n ...config,\n agents: {\n ...defaults.agents,\n ...config.agents,\n available: {\n ...defaults.agents.available,\n ...config.agents?.available,\n },\n },\n secrets: {\n ...defaults.secrets,\n ...config.secrets,\n },\n context: {\n ...defaults.context,\n ...config.context,\n },\n };\n}\n","/**\n * Agent detection and management\n */\n\nimport { execa } from 'execa';\nimport which from 'which';\nimport type { AgentDefinition, AgentStatus, RapidConfig } from './types.js';\n\n/**\n * Check if an agent CLI is available\n */\nexport async function checkAgentAvailable(agent: AgentDefinition): Promise<AgentStatus> {\n try {\n const cliPath = await which(agent.cli);\n\n // Try to get version\n let version: string | undefined;\n try {\n const result = await execa(agent.cli, ['--version'], { timeout: 5000 });\n version = result.stdout.trim().split('\\n')[0];\n } catch {\n // Version check failed, but CLI exists\n }\n\n return {\n name: agent.cli,\n available: true,\n cliPath,\n ...(version !== undefined && { version }),\n };\n } catch {\n return {\n name: agent.cli,\n available: false,\n };\n }\n}\n\n/**\n * Check all configured agents\n */\nexport async function checkAllAgents(config: RapidConfig): Promise<AgentStatus[]> {\n const results: AgentStatus[] = [];\n\n for (const [name, agent] of Object.entries(config.agents.available)) {\n const status = await checkAgentAvailable(agent);\n results.push({\n ...status,\n name,\n });\n }\n\n return results;\n}\n\n/**\n * Get the default agent from config\n */\nexport function getDefaultAgent(config: RapidConfig): AgentDefinition | null {\n const defaultName = config.agents.default;\n return config.agents.available[defaultName] || null;\n}\n\n/**\n * Get a specific agent by name\n */\nexport function getAgent(config: RapidConfig, name: string): AgentDefinition | null {\n return config.agents.available[name] || null;\n}\n\n/**\n * Launch an agent CLI\n */\nexport async function launchAgent(\n agent: AgentDefinition,\n options: {\n cwd?: string;\n env?: Record<string, string>;\n stdio?: 'inherit' | 'pipe';\n } = {}\n): Promise<void> {\n const args = agent.args ?? [];\n const cwd = options.cwd ?? process.cwd();\n\n await execa(agent.cli, args, {\n cwd,\n env: {\n ...process.env,\n ...options.env,\n },\n stdio: options.stdio ?? 'inherit',\n });\n}\n","/**\n * Logging utilities\n */\n\nimport chalk from 'chalk';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet currentLevel: LogLevel = 'info';\n\nexport function setLogLevel(level: LogLevel): void {\n currentLevel = level;\n}\n\nexport function getLogLevel(): LogLevel {\n return currentLevel;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\n}\n\nexport const logger = {\n debug(message: string, ...args: unknown[]): void {\n if (shouldLog('debug')) {\n console.log(chalk.gray(`[debug] ${message}`), ...args);\n }\n },\n\n info(message: string, ...args: unknown[]): void {\n if (shouldLog('info')) {\n console.log(chalk.blue('ℹ'), message, ...args);\n }\n },\n\n success(message: string, ...args: unknown[]): void {\n if (shouldLog('info')) {\n console.log(chalk.green('✓'), message, ...args);\n }\n },\n\n warn(message: string, ...args: unknown[]): void {\n if (shouldLog('warn')) {\n console.log(chalk.yellow('⚠'), message, ...args);\n }\n },\n\n error(message: string, ...args: unknown[]): void {\n if (shouldLog('error')) {\n console.error(chalk.red('✗'), message, ...args);\n }\n },\n\n // Styled output helpers\n brand(text: string): string {\n return chalk.hex('#818cf8')(text);\n },\n\n dim(text: string): string {\n return chalk.dim(text);\n },\n\n bold(text: string): string {\n return chalk.bold(text);\n },\n\n // Print a header\n header(text: string): void {\n console.log();\n console.log(chalk.bold(text));\n console.log(chalk.dim('─'.repeat(text.length)));\n },\n\n // Print a blank line\n blank(): void {\n console.log();\n },\n};\n","/**\n * Container management utilities\n * Uses devcontainer CLI for container lifecycle\n */\n\nimport { execa, type ExecaError } from 'execa';\nimport which from 'which';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { RapidConfig } from './types.js';\n\nexport interface ContainerStatus {\n exists: boolean;\n running: boolean;\n containerId?: string;\n containerName?: string;\n}\n\nexport interface DevcontainerConfig {\n name?: string;\n image?: string;\n dockerFile?: string;\n build?: {\n dockerfile?: string;\n context?: string;\n };\n [key: string]: unknown;\n}\n\n/**\n * Check if devcontainer CLI is available\n */\nexport async function hasDevcontainerCli(): Promise<boolean> {\n try {\n await which('devcontainer');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if Docker is available\n */\nexport async function hasDocker(): Promise<boolean> {\n try {\n await execa('docker', ['info'], { timeout: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the devcontainer.json path\n */\nexport function getDevcontainerPath(rootDir: string, config?: RapidConfig): string {\n const customPath = config?.container?.devcontainer;\n if (customPath) {\n return join(rootDir, customPath);\n }\n return join(rootDir, '.devcontainer', 'devcontainer.json');\n}\n\n/**\n * Load devcontainer.json\n */\nexport async function loadDevcontainerConfig(\n rootDir: string,\n config?: RapidConfig\n): Promise<DevcontainerConfig | null> {\n try {\n const configPath = getDevcontainerPath(rootDir, config);\n const content = await readFile(configPath, 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\n/**\n * Get container name for a project\n */\nexport function getContainerName(rootDir: string, devcontainerConfig?: DevcontainerConfig): string {\n // Use devcontainer name if available, otherwise derive from directory\n const dirName = rootDir.split('/').pop() || 'rapid';\n const name = devcontainerConfig?.name || dirName;\n // Sanitize for Docker container name\n return `rapid-${name}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n\n/**\n * Check container status using devcontainer labels\n */\nexport async function getContainerStatus(\n rootDir: string,\n _config?: RapidConfig\n): Promise<ContainerStatus> {\n try {\n // Use devcontainer label to find the container (this is how devcontainer CLI tracks containers)\n const result = await execa('docker', [\n 'ps',\n '-a',\n '--filter',\n `label=devcontainer.local_folder=${rootDir}`,\n '--format',\n '{{.ID}}\\t{{.State}}\\t{{.Names}}',\n ]);\n\n const lines = result.stdout.trim().split('\\n').filter(Boolean);\n if (lines.length === 0) {\n return { exists: false, running: false };\n }\n\n const parts = lines[0]?.split('\\t');\n const containerId = parts?.[0];\n const state = parts?.[1];\n const containerName = parts?.[2];\n\n if (!containerId || !containerName) {\n return { exists: false, running: false };\n }\n\n return {\n exists: true,\n running: state === 'running',\n containerId,\n containerName,\n };\n } catch {\n return { exists: false, running: false };\n }\n}\n\n/**\n * Start the dev container using devcontainer CLI\n */\nexport async function startContainer(\n rootDir: string,\n _config?: RapidConfig,\n options: { rebuild?: boolean; quiet?: boolean } = {}\n): Promise<{ success: boolean; containerId?: string; error?: string }> {\n const hasDevCli = await hasDevcontainerCli();\n\n if (!hasDevCli) {\n return {\n success: false,\n error: 'devcontainer CLI not found. Install with: npm install -g @devcontainers/cli',\n };\n }\n\n const hasDockerRunning = await hasDocker();\n if (!hasDockerRunning) {\n return {\n success: false,\n error: 'Docker is not running. Please start Docker Desktop.',\n };\n }\n\n try {\n const args = ['up', '--workspace-folder', rootDir];\n\n if (options.rebuild) {\n args.push('--remove-existing-container');\n }\n\n const result = await execa('devcontainer', args, {\n stdio: options.quiet ? 'pipe' : 'inherit',\n cwd: rootDir,\n });\n\n // Parse the container ID from output\n // devcontainer up outputs JSON with containerId\n if (options.quiet && result.stdout) {\n try {\n const output = JSON.parse(result.stdout);\n return { success: true, containerId: output.containerId };\n } catch {\n return { success: true };\n }\n }\n\n return { success: true };\n } catch (error) {\n const execError = error as ExecaError;\n const stderr = typeof execError.stderr === 'string' ? execError.stderr : undefined;\n return {\n success: false,\n error: stderr || execError.message,\n };\n }\n}\n\n/**\n * Stop the dev container\n */\nexport async function stopContainer(\n rootDir: string,\n config?: RapidConfig,\n options: { remove?: boolean } = {}\n): Promise<{ success: boolean; error?: string }> {\n const status = await getContainerStatus(rootDir, config);\n\n if (!status.exists) {\n return { success: true }; // Nothing to stop\n }\n\n try {\n if (status.running) {\n await execa('docker', ['stop', status.containerId!]);\n }\n\n if (options.remove) {\n await execa('docker', ['rm', status.containerId!]);\n }\n\n return { success: true };\n } catch (error) {\n const execError = error as ExecaError;\n const stderr = typeof execError.stderr === 'string' ? execError.stderr : undefined;\n return {\n success: false,\n error: stderr || execError.message,\n };\n }\n}\n\n/**\n * Execute a command inside the dev container\n */\nexport async function execInContainer(\n rootDir: string,\n command: string[],\n _config?: RapidConfig,\n options: { interactive?: boolean; tty?: boolean; env?: Record<string, string> } = {}\n): Promise<void> {\n const hasDevCli = await hasDevcontainerCli();\n\n if (!hasDevCli) {\n throw new Error('devcontainer CLI not found. Install with: npm install -g @devcontainers/cli');\n }\n\n const args = ['exec', '--workspace-folder', rootDir];\n\n // Add environment variables\n if (options.env) {\n for (const [key, value] of Object.entries(options.env)) {\n args.push('--remote-env', `${key}=${value}`);\n }\n }\n\n // Add the command\n args.push(...command);\n\n await execa('devcontainer', args, {\n stdio: 'inherit',\n cwd: rootDir,\n });\n}\n","/**\n * Secrets management for RAPID\n * Supports 1Password, HashiCorp Vault, and environment variables\n */\n\nimport { spawn } from 'node:child_process';\nimport { readFile, writeFile, access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { SecretsConfig } from './types.js';\nimport { logger } from './logger.js';\n\nexport interface SecretStatus {\n name: string;\n reference: string;\n provider: 'env' | '1password' | 'vault';\n available: boolean;\n error?: string;\n}\n\nexport interface SecretsStatus {\n provider: 'env' | '1password' | 'vault';\n authenticated: boolean;\n authMethod?: 'service-account' | 'user' | 'token';\n secrets: SecretStatus[];\n allAvailable: boolean;\n}\n\nexport interface OpAuthStatus {\n authenticated: boolean;\n method: 'service-account' | 'user' | 'none';\n accountInfo?: string;\n}\n\n/**\n * Execute a command and return stdout\n */\nasync function execCommand(\n command: string,\n args: string[],\n options: { timeout?: number } = {}\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n return new Promise((resolve) => {\n const proc = spawn(command, args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: options.timeout ?? 30000,\n });\n\n let stdout = '';\n let stderr = '';\n\n proc.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n stderr += data.toString();\n });\n\n proc.on('close', (code) => {\n resolve({ stdout: stdout.trim(), stderr: stderr.trim(), exitCode: code ?? 1 });\n });\n\n proc.on('error', (err) => {\n resolve({ stdout: '', stderr: err.message, exitCode: 1 });\n });\n });\n}\n\n/**\n * Check if 1Password CLI is installed\n */\nexport async function hasOpCli(): Promise<boolean> {\n const result = await execCommand('op', ['--version']);\n return result.exitCode === 0;\n}\n\n/**\n * Check if OP_SERVICE_ACCOUNT_TOKEN is set\n */\nexport function hasOpServiceAccountToken(): boolean {\n return !!process.env.OP_SERVICE_ACCOUNT_TOKEN;\n}\n\n/**\n * Check if 1Password CLI is authenticated (via service account or user)\n */\nexport async function isOpAuthenticated(): Promise<boolean> {\n // Service account token takes precedence\n if (hasOpServiceAccountToken()) {\n // Verify the token works by trying to list vaults\n const result = await execCommand('op', ['vault', 'list', '--format=json']);\n return result.exitCode === 0;\n }\n\n // Fall back to user authentication\n const result = await execCommand('op', ['account', 'list']);\n return result.exitCode === 0 && result.stdout.length > 0;\n}\n\n/**\n * Get detailed 1Password authentication status\n */\nexport async function getOpAuthStatus(): Promise<OpAuthStatus> {\n // Check for service account token first\n if (hasOpServiceAccountToken()) {\n const result = await execCommand('op', ['vault', 'list', '--format=json']);\n if (result.exitCode === 0) {\n return {\n authenticated: true,\n method: 'service-account',\n accountInfo: 'Service Account',\n };\n }\n return {\n authenticated: false,\n method: 'none',\n accountInfo: 'Invalid service account token',\n };\n }\n\n // Check for user authentication\n const result = await execCommand('op', ['account', 'list', '--format=json']);\n if (result.exitCode === 0 && result.stdout.length > 0) {\n try {\n const accounts = JSON.parse(result.stdout);\n if (accounts.length > 0) {\n return {\n authenticated: true,\n method: 'user',\n accountInfo: accounts[0].email || accounts[0].url,\n };\n }\n } catch {\n // Parse error, but command succeeded\n return {\n authenticated: true,\n method: 'user',\n };\n }\n }\n\n return {\n authenticated: false,\n method: 'none',\n };\n}\n\n/**\n * Check if HashiCorp Vault CLI is installed\n */\nexport async function hasVaultCli(): Promise<boolean> {\n const result = await execCommand('vault', ['--version']);\n return result.exitCode === 0;\n}\n\n/**\n * Check if HashiCorp Vault is authenticated\n */\nexport async function isVaultAuthenticated(): Promise<boolean> {\n const result = await execCommand('vault', ['token', 'lookup']);\n return result.exitCode === 0;\n}\n\n/**\n * Read a secret from 1Password\n * @param reference - 1Password reference (e.g., \"op://vault/item/field\")\n */\nexport async function readOpSecret(reference: string): Promise<string | null> {\n const result = await execCommand('op', ['read', reference]);\n if (result.exitCode !== 0) {\n return null;\n }\n return result.stdout;\n}\n\n/**\n * Read a secret from HashiCorp Vault\n * @param path - Vault path (e.g., \"secret/data/myproject\")\n * @param field - Field name within the secret\n */\nexport async function readVaultSecret(path: string, field: string): Promise<string | null> {\n const result = await execCommand('vault', ['kv', 'get', '-field', field, path]);\n if (result.exitCode !== 0) {\n return null;\n }\n return result.stdout;\n}\n\n/**\n * Verify a single secret is accessible\n */\nexport async function verifySecret(\n name: string,\n reference: string,\n provider: 'env' | '1password' | 'vault',\n config?: SecretsConfig\n): Promise<SecretStatus> {\n const status: SecretStatus = {\n name,\n reference,\n provider,\n available: false,\n };\n\n try {\n switch (provider) {\n case 'env': {\n const value = process.env[name];\n status.available = !!value && value.length > 0;\n if (!status.available) {\n status.error = 'Environment variable not set';\n }\n break;\n }\n\n case '1password': {\n // Reference should be in format op://vault/item/field\n const value = await readOpSecret(reference);\n status.available = value !== null;\n if (!status.available) {\n status.error = 'Secret not found in 1Password';\n }\n break;\n }\n\n case 'vault': {\n // Parse path and field from reference\n const field = reference.split('/').pop() || 'value';\n const vaultPath = reference.includes('/')\n ? reference.substring(0, reference.lastIndexOf('/'))\n : config?.vault || 'secret/data/default';\n\n const value = await readVaultSecret(vaultPath, field);\n status.available = value !== null;\n if (!status.available) {\n status.error = 'Secret not found in Vault';\n }\n break;\n }\n }\n } catch (error) {\n status.error = error instanceof Error ? error.message : String(error);\n status.available = false;\n }\n\n return status;\n}\n\n/**\n * Verify all secrets in configuration\n */\nexport async function verifySecrets(config: SecretsConfig): Promise<SecretsStatus> {\n const provider = config.provider || 'env';\n let authenticated = true;\n\n // Check authentication status for provider\n switch (provider) {\n case '1password':\n authenticated = await isOpAuthenticated();\n break;\n case 'vault':\n authenticated = await isVaultAuthenticated();\n break;\n case 'env':\n authenticated = true;\n break;\n }\n\n const secrets: SecretStatus[] = [];\n\n if (config.items) {\n for (const [name, reference] of Object.entries(config.items)) {\n const status = await verifySecret(name, reference, provider, config);\n secrets.push(status);\n }\n }\n\n const allAvailable = secrets.length === 0 || secrets.every((s) => s.available);\n\n return {\n provider,\n authenticated,\n secrets,\n allAvailable,\n };\n}\n\n/**\n * Load all secrets into environment\n */\nexport async function loadSecrets(config: SecretsConfig): Promise<Record<string, string>> {\n const provider = config.provider || 'env';\n const secrets: Record<string, string> = {};\n\n if (!config.items) {\n return secrets;\n }\n\n for (const [name, reference] of Object.entries(config.items)) {\n try {\n let value: string | null = null;\n\n switch (provider) {\n case 'env':\n value = process.env[name] || null;\n break;\n\n case '1password':\n value = await readOpSecret(reference);\n break;\n\n case 'vault': {\n const field = reference.split('/').pop() || 'value';\n const path = reference.substring(0, reference.lastIndexOf('/')) || config.vault || '';\n value = await readVaultSecret(path, field);\n break;\n }\n }\n\n if (value) {\n secrets[name] = value;\n }\n } catch (error) {\n logger.debug(`Failed to load secret ${name}: ${error}`);\n }\n }\n\n return secrets;\n}\n\n/**\n * Generate .envrc file from secrets configuration\n */\nexport function generateEnvrc(config: SecretsConfig): string {\n const provider = config.provider || 'env';\n const lines: string[] = [\n '# .envrc - RAPID project secrets',\n '# This file is safe to commit - it contains NO secrets, only references',\n '#',\n `# Provider: ${provider}`,\n `# Generated by: rapid secrets generate`,\n '',\n ];\n\n if (!config.items || Object.keys(config.items).length === 0) {\n lines.push('# No secrets configured in rapid.json');\n return lines.join('\\n');\n }\n\n switch (provider) {\n case '1password':\n lines.push('# Secrets loaded from 1Password');\n lines.push('# Requires: 1Password CLI (op) installed and authenticated');\n lines.push('');\n for (const [name, reference] of Object.entries(config.items)) {\n lines.push(`export ${name}=$(op read \"${reference}\")`);\n }\n break;\n\n case 'vault':\n lines.push('# Secrets loaded from HashiCorp Vault');\n lines.push('# Requires: Vault CLI installed and authenticated');\n lines.push('');\n if (config.address) {\n lines.push(`export VAULT_ADDR=\"${config.address}\"`);\n lines.push('');\n }\n for (const [name, reference] of Object.entries(config.items)) {\n const path = config.vault || 'secret/data/default';\n lines.push(`export ${name}=$(vault kv get -field=${reference} ${path})`);\n }\n break;\n\n case 'env':\n lines.push('# WARNING: env provider expects secrets to be set manually');\n lines.push('# Consider using 1password or vault for better security');\n lines.push('');\n lines.push('# Uncomment and set values (DO NOT commit actual values!)');\n for (const name of Object.keys(config.items)) {\n lines.push(`# export ${name}=\"your-value-here\"`);\n }\n break;\n }\n\n // Add .env.local loading if configured\n if (config.envrc?.includeLocal !== false) {\n lines.push('');\n lines.push('# Load local overrides if present');\n lines.push('[[ -f .env.local ]] && source_env .env.local');\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n\n/**\n * Write .envrc file to project directory\n */\nexport async function writeEnvrc(rootDir: string, config: SecretsConfig): Promise<string> {\n const envrcPath = config.envrc?.path || '.envrc';\n const fullPath = join(rootDir, envrcPath);\n const content = generateEnvrc(config);\n\n await writeFile(fullPath, content);\n return fullPath;\n}\n\n/**\n * Check if .envrc exists in project\n */\nexport async function hasEnvrc(rootDir: string, config?: SecretsConfig): Promise<boolean> {\n const envrcPath = config?.envrc?.path || '.envrc';\n const fullPath = join(rootDir, envrcPath);\n\n try {\n await access(fullPath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Read existing .envrc content\n */\nexport async function readEnvrc(rootDir: string, config?: SecretsConfig): Promise<string | null> {\n const envrcPath = config?.envrc?.path || '.envrc';\n const fullPath = join(rootDir, envrcPath);\n\n try {\n const content = await readFile(fullPath, 'utf-8');\n return content;\n } catch {\n return null;\n }\n}\n\n/**\n * Get a summary of provider requirements\n */\nexport function getProviderInfo(provider: 'env' | '1password' | 'vault'): {\n name: string;\n cliRequired: string | null;\n authCommand: string | null;\n installUrl: string | null;\n} {\n switch (provider) {\n case '1password':\n return {\n name: '1Password',\n cliRequired: 'op',\n authCommand: 'eval $(op signin)',\n installUrl: 'https://developer.1password.com/docs/cli/get-started/',\n };\n case 'vault':\n return {\n name: 'HashiCorp Vault',\n cliRequired: 'vault',\n authCommand: 'vault login',\n installUrl: 'https://developer.hashicorp.com/vault/docs/install',\n };\n case 'env':\n return {\n name: 'Environment Variables',\n cliRequired: null,\n authCommand: null,\n installUrl: null,\n };\n }\n}\n"],"mappings":"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","names":["execa","which","readFile","readFile","join","resolve","result","join","readFile"]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/agents.ts","../src/external-auth.ts","../src/logger.ts","../src/container.ts","../src/secrets.ts"],"sourcesContent":["/**\n * Configuration loading and validation\n */\n\nimport { cosmiconfig } from 'cosmiconfig';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport type { RapidConfig } from './types.js';\n\nconst CONFIG_NAME = 'rapid';\nconst CONFIG_FILES = ['rapid.json', 'rapid.config.json', '.rapidrc', '.rapidrc.json'];\n\nexport interface LoadedConfig {\n config: RapidConfig;\n filepath: string;\n rootDir: string;\n}\n\n/**\n * Load RAPID configuration from the current directory or ancestors\n */\nexport async function loadConfig(cwd?: string): Promise<LoadedConfig | null> {\n const explorer = cosmiconfig(CONFIG_NAME, {\n searchPlaces: CONFIG_FILES,\n loaders: {\n '.json': async (filepath) => {\n const content = await readFile(filepath, 'utf-8');\n return JSON.parse(content);\n },\n },\n });\n\n const result = await explorer.search(cwd);\n\n if (!result || result.isEmpty) {\n return null;\n }\n\n return {\n config: result.config as RapidConfig,\n filepath: result.filepath,\n rootDir: dirname(result.filepath),\n };\n}\n\n/**\n * Load configuration from a specific file\n */\nexport async function loadConfigFromFile(filepath: string): Promise<LoadedConfig> {\n const content = await readFile(filepath, 'utf-8');\n const config = JSON.parse(content) as RapidConfig;\n\n return {\n config,\n filepath: resolve(filepath),\n rootDir: dirname(resolve(filepath)),\n };\n}\n\n/**\n * Get default configuration\n */\nexport function getDefaultConfig(): RapidConfig {\n return {\n version: '1.0',\n agents: {\n default: 'claude',\n available: {\n claude: {\n cli: 'claude',\n instructionFile: 'CLAUDE.md',\n envVars: ['ANTHROPIC_API_KEY'],\n },\n opencode: {\n cli: 'opencode',\n instructionFile: 'AGENTS.md',\n envVars: ['ANTHROPIC_API_KEY'],\n },\n aider: {\n cli: 'aider',\n instructionFile: 'AGENTS.md',\n envVars: ['ANTHROPIC_API_KEY'],\n args: ['--model', 'claude-3-5-sonnet-20241022'],\n },\n },\n },\n secrets: {\n provider: 'env',\n },\n context: {\n files: ['README.md'],\n dirs: ['docs/'],\n generateAgentFiles: true,\n },\n };\n}\n\n/**\n * Merge user config with defaults\n */\nexport function mergeWithDefaults(config: Partial<RapidConfig>): RapidConfig {\n const defaults = getDefaultConfig();\n\n return {\n ...defaults,\n ...config,\n agents: {\n ...defaults.agents,\n ...config.agents,\n available: {\n ...defaults.agents.available,\n ...config.agents?.available,\n },\n },\n secrets: {\n ...defaults.secrets,\n ...config.secrets,\n },\n context: {\n ...defaults.context,\n ...config.context,\n },\n };\n}\n","/**\n * Agent detection and management\n */\n\nimport { execa } from 'execa';\nimport which from 'which';\nimport type { AgentDefinition, AgentStatus, RapidConfig, ExternalAuthConfig } from './types.js';\nimport { getAuthEnvironment } from './external-auth.js';\n\n/**\n * Check if an agent CLI is available\n */\nexport async function checkAgentAvailable(agent: AgentDefinition): Promise<AgentStatus> {\n try {\n const cliPath = await which(agent.cli);\n\n // Try to get version\n let version: string | undefined;\n try {\n const result = await execa(agent.cli, ['--version'], { timeout: 5000 });\n version = result.stdout.trim().split('\\n')[0];\n } catch {\n // Version check failed, but CLI exists\n }\n\n return {\n name: agent.cli,\n available: true,\n cliPath,\n ...(version !== undefined && { version }),\n };\n } catch {\n return {\n name: agent.cli,\n available: false,\n };\n }\n}\n\n/**\n * Check all configured agents\n */\nexport async function checkAllAgents(config: RapidConfig): Promise<AgentStatus[]> {\n const results: AgentStatus[] = [];\n\n for (const [name, agent] of Object.entries(config.agents.available)) {\n const status = await checkAgentAvailable(agent);\n results.push({\n ...status,\n name,\n });\n }\n\n return results;\n}\n\n/**\n * Get the default agent from config\n */\nexport function getDefaultAgent(config: RapidConfig): AgentDefinition | null {\n const defaultName = config.agents.default;\n return config.agents.available[defaultName] || null;\n}\n\n/**\n * Get a specific agent by name\n */\nexport function getAgent(config: RapidConfig, name: string): AgentDefinition | null {\n return config.agents.available[name] || null;\n}\n\n/**\n * Launch an agent CLI\n */\nexport async function launchAgent(\n agent: AgentDefinition,\n options: {\n cwd?: string;\n env?: Record<string, string>;\n stdio?: 'inherit' | 'pipe';\n useExternalAuth?: boolean;\n externalAuthConfig?: ExternalAuthConfig;\n } = {}\n): Promise<void> {\n const args = agent.args ?? [];\n const cwd = options.cwd ?? process.cwd();\n\n // Get external auth environment if enabled\n let authEnv: Record<string, string> = {};\n if (options.useExternalAuth !== false) {\n authEnv = await getAuthEnvironment(options.externalAuthConfig);\n }\n\n await execa(agent.cli, args, {\n cwd,\n env: {\n ...process.env,\n ...authEnv,\n ...options.env, // User-provided env takes precedence\n },\n stdio: options.stdio ?? 'inherit',\n });\n}\n","/**\n * External Authentication Detection\n *\n * Detects and reuses credentials from AI coding tools like:\n * - Claude Code (~/.claude.json)\n * - OpenAI Codex (~/.codex/auth.json)\n * - Gemini CLI (~/.gemini/)\n * - Aider (.env files with API keys)\n */\n\nimport { readFile, access } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DetectedCredential, ExternalAuthConfig, AuthStatus } from './types.js';\nimport { logger } from './logger.js';\n\n/**\n * Default configuration for external auth detection\n */\nconst DEFAULT_CONFIG: ExternalAuthConfig = {\n enabled: true,\n sources: ['claude-code', 'codex', 'gemini-cli', 'aider', 'env'],\n};\n\n/**\n * Check if a file exists\n */\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Safely read and parse JSON file\n */\nasync function readJsonFile<T>(path: string): Promise<T | null> {\n try {\n const content = await readFile(path, 'utf-8');\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\n// =============================================================================\n// Claude Code Detection\n// =============================================================================\n\ninterface ClaudeCodeConfig {\n oauthAccount?: {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: string;\n accountUuid?: string;\n emailAddress?: string;\n organizationName?: string;\n planType?: string;\n };\n claudeAiOauth?: {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: string;\n };\n lastAccountUuid?: string;\n}\n\n/**\n * Detect Claude Code credentials from ~/.claude.json\n */\nexport async function detectClaudeCodeAuth(): Promise<DetectedCredential | null> {\n const home = homedir();\n const configPath = join(home, '.claude.json');\n\n if (!(await fileExists(configPath))) {\n return null;\n }\n\n const config = await readJsonFile<ClaudeCodeConfig>(configPath);\n if (!config) {\n return null;\n }\n\n // Check for OAuth session (Claude Pro/Max login)\n const oauth = config.oauthAccount || config.claudeAiOauth;\n if (oauth?.accessToken) {\n const expiresAt = oauth.expiresAt ? new Date(oauth.expiresAt) : undefined;\n\n // Check if token is expired\n if (expiresAt && expiresAt < new Date()) {\n logger.debug('Claude Code OAuth token expired');\n return null;\n }\n\n const cred: DetectedCredential = {\n source: 'claude-code',\n provider: 'anthropic',\n authType: 'oauth',\n value: oauth.accessToken,\n configPath,\n };\n\n if (expiresAt) {\n cred.expiresAt = expiresAt;\n }\n\n const accountInfo: {\n email?: string;\n organization?: string;\n plan?: string;\n } = {};\n\n if (config.oauthAccount?.emailAddress) {\n accountInfo.email = config.oauthAccount.emailAddress;\n }\n if (config.oauthAccount?.organizationName) {\n accountInfo.organization = config.oauthAccount.organizationName;\n }\n if (config.oauthAccount?.planType) {\n accountInfo.plan = config.oauthAccount.planType;\n }\n\n if (Object.keys(accountInfo).length > 0) {\n cred.accountInfo = accountInfo;\n }\n\n return cred;\n }\n\n // Check for API key in environment (Claude Code also respects ANTHROPIC_API_KEY)\n const apiKey = process.env.ANTHROPIC_API_KEY;\n if (apiKey) {\n return {\n source: 'claude-code',\n provider: 'anthropic',\n authType: 'api-key',\n envVar: 'ANTHROPIC_API_KEY',\n value: apiKey,\n configPath,\n };\n }\n\n return null;\n}\n\n// =============================================================================\n// OpenAI Codex Detection\n// =============================================================================\n\ninterface CodexAuthConfig {\n chatgpt?: {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: string;\n email?: string;\n workspaceId?: string;\n };\n api?: {\n apiKey?: string;\n };\n}\n\n/**\n * Detect OpenAI Codex credentials from ~/.codex/auth.json\n */\nexport async function detectCodexAuth(): Promise<DetectedCredential | null> {\n const home = homedir();\n const configPath = join(home, '.codex', 'auth.json');\n\n if (!(await fileExists(configPath))) {\n return null;\n }\n\n const config = await readJsonFile<CodexAuthConfig>(configPath);\n if (!config) {\n return null;\n }\n\n // Check for ChatGPT OAuth session\n if (config.chatgpt?.accessToken) {\n const expiresAt = config.chatgpt.expiresAt ? new Date(config.chatgpt.expiresAt) : undefined;\n\n // Check if token is expired\n if (expiresAt && expiresAt < new Date()) {\n logger.debug('Codex ChatGPT OAuth token expired');\n return null;\n }\n\n const cred: DetectedCredential = {\n source: 'codex',\n provider: 'openai',\n authType: 'oauth',\n value: config.chatgpt.accessToken,\n configPath,\n };\n\n if (expiresAt) {\n cred.expiresAt = expiresAt;\n }\n\n const accountInfo: {\n email?: string;\n organization?: string;\n plan?: string;\n } = {};\n\n if (config.chatgpt.email) {\n accountInfo.email = config.chatgpt.email;\n }\n if (config.chatgpt.workspaceId) {\n accountInfo.organization = config.chatgpt.workspaceId;\n }\n\n if (Object.keys(accountInfo).length > 0) {\n cred.accountInfo = accountInfo;\n }\n\n return cred;\n }\n\n // Check for API key\n if (config.api?.apiKey) {\n return {\n source: 'codex',\n provider: 'openai',\n authType: 'api-key',\n value: config.api.apiKey,\n configPath,\n };\n }\n\n // Check environment variable\n const apiKey = process.env.OPENAI_API_KEY;\n if (apiKey) {\n return {\n source: 'codex',\n provider: 'openai',\n authType: 'api-key',\n envVar: 'OPENAI_API_KEY',\n value: apiKey,\n };\n }\n\n return null;\n}\n\n// =============================================================================\n// Gemini CLI Detection\n// =============================================================================\n\ninterface GeminiSettings {\n auth?: {\n oauth?: {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: string;\n email?: string;\n };\n };\n googleCloudProject?: string;\n}\n\n/**\n * Detect Gemini CLI credentials from ~/.gemini/\n */\nexport async function detectGeminiAuth(): Promise<DetectedCredential | null> {\n const home = homedir();\n const settingsPath = join(home, '.gemini', 'settings.json');\n\n // Check for settings.json with OAuth\n if (await fileExists(settingsPath)) {\n const settings = await readJsonFile<GeminiSettings>(settingsPath);\n if (settings?.auth?.oauth?.accessToken) {\n const oauth = settings.auth.oauth;\n const expiresAt = oauth.expiresAt ? new Date(oauth.expiresAt) : undefined;\n\n if (expiresAt && expiresAt < new Date()) {\n logger.debug('Gemini CLI OAuth token expired');\n } else {\n const cred: DetectedCredential = {\n source: 'gemini-cli',\n provider: 'google',\n authType: 'oauth',\n value: oauth.accessToken!,\n configPath: settingsPath,\n };\n\n if (expiresAt) {\n cred.expiresAt = expiresAt;\n }\n\n const accountInfo: {\n email?: string;\n organization?: string;\n plan?: string;\n } = {};\n\n if (oauth.email) {\n accountInfo.email = oauth.email;\n }\n if (settings.googleCloudProject) {\n accountInfo.organization = settings.googleCloudProject;\n }\n\n if (Object.keys(accountInfo).length > 0) {\n cred.accountInfo = accountInfo;\n }\n\n return cred;\n }\n }\n }\n\n // Check for GEMINI_API_KEY environment variable\n const geminiKey = process.env.GEMINI_API_KEY;\n if (geminiKey) {\n return {\n source: 'gemini-cli',\n provider: 'google',\n authType: 'api-key',\n envVar: 'GEMINI_API_KEY',\n value: geminiKey,\n };\n }\n\n // Check for GOOGLE_API_KEY environment variable\n const googleKey = process.env.GOOGLE_API_KEY;\n if (googleKey) {\n return {\n source: 'gemini-cli',\n provider: 'google',\n authType: 'api-key',\n envVar: 'GOOGLE_API_KEY',\n value: googleKey,\n };\n }\n\n return null;\n}\n\n// =============================================================================\n// Aider Detection\n// =============================================================================\n\n/**\n * Detect Aider credentials from environment variables\n * Aider uses standard environment variables, no config file\n */\nexport async function detectAiderAuth(): Promise<DetectedCredential[]> {\n const credentials: DetectedCredential[] = [];\n\n // Anthropic API Key (Aider's preferred for Claude models)\n const anthropicKey = process.env.ANTHROPIC_API_KEY;\n if (anthropicKey) {\n credentials.push({\n source: 'aider',\n provider: 'anthropic',\n authType: 'api-key',\n envVar: 'ANTHROPIC_API_KEY',\n value: anthropicKey,\n });\n }\n\n // OpenAI API Key\n const openaiKey = process.env.OPENAI_API_KEY;\n if (openaiKey) {\n credentials.push({\n source: 'aider',\n provider: 'openai',\n authType: 'api-key',\n envVar: 'OPENAI_API_KEY',\n value: openaiKey,\n });\n }\n\n // Gemini API Key (Aider also supports Gemini)\n const geminiKey = process.env.GEMINI_API_KEY;\n if (geminiKey) {\n credentials.push({\n source: 'aider',\n provider: 'google',\n authType: 'api-key',\n envVar: 'GEMINI_API_KEY',\n value: geminiKey,\n });\n }\n\n return credentials;\n}\n\n// =============================================================================\n// Environment Variable Detection\n// =============================================================================\n\n/**\n * Detect credentials from standard environment variables\n */\nexport async function detectEnvAuth(): Promise<DetectedCredential[]> {\n const credentials: DetectedCredential[] = [];\n\n const envMappings: Array<{\n envVar: string;\n provider: 'anthropic' | 'openai' | 'google';\n }> = [\n { envVar: 'ANTHROPIC_API_KEY', provider: 'anthropic' },\n { envVar: 'OPENAI_API_KEY', provider: 'openai' },\n { envVar: 'GEMINI_API_KEY', provider: 'google' },\n { envVar: 'GOOGLE_API_KEY', provider: 'google' },\n ];\n\n for (const { envVar, provider } of envMappings) {\n const value = process.env[envVar];\n if (value) {\n credentials.push({\n source: 'env',\n provider,\n authType: 'api-key',\n envVar,\n value,\n });\n }\n }\n\n return credentials;\n}\n\n// =============================================================================\n// Main Detection Functions\n// =============================================================================\n\n/**\n * Detect all available credentials from external sources\n */\nexport async function detectAllCredentials(\n config: ExternalAuthConfig = DEFAULT_CONFIG\n): Promise<DetectedCredential[]> {\n if (!config.enabled) {\n return [];\n }\n\n const sources = config.sources || DEFAULT_CONFIG.sources!;\n const credentials: DetectedCredential[] = [];\n const seenValues = new Set<string>();\n\n for (const source of sources) {\n try {\n let detected: DetectedCredential | DetectedCredential[] | null = null;\n\n switch (source) {\n case 'claude-code':\n detected = await detectClaudeCodeAuth();\n break;\n case 'codex':\n detected = await detectCodexAuth();\n break;\n case 'gemini-cli':\n detected = await detectGeminiAuth();\n break;\n case 'aider':\n detected = await detectAiderAuth();\n break;\n case 'env':\n detected = await detectEnvAuth();\n break;\n }\n\n if (detected) {\n const items = Array.isArray(detected) ? detected : [detected];\n for (const item of items) {\n // Deduplicate by value to avoid listing the same API key multiple times\n const key = item.value || item.envVar || '';\n if (key && !seenValues.has(key)) {\n seenValues.add(key);\n credentials.push(item);\n }\n }\n }\n } catch (error) {\n logger.debug(`Error detecting ${source} credentials:`, error);\n }\n }\n\n return credentials;\n}\n\n/**\n * Get authentication status summary\n */\nexport async function getAuthStatus(\n config: ExternalAuthConfig = DEFAULT_CONFIG\n): Promise<AuthStatus> {\n const credentials = await detectAllCredentials(config);\n const warnings: string[] = [];\n\n // Check for expired tokens\n for (const cred of credentials) {\n if (cred.expiresAt && cred.expiresAt < new Date()) {\n warnings.push(`${cred.source} OAuth token has expired. Please re-authenticate.`);\n }\n }\n\n // Find preferred source\n let preferredSource: DetectedCredential | undefined;\n if (config.preferSource) {\n preferredSource = credentials.find((c) => c.source === config.preferSource);\n }\n\n // If no preferred source specified, prioritize OAuth over API keys\n if (!preferredSource && credentials.length > 0) {\n preferredSource = credentials.find((c) => c.authType === 'oauth') || credentials[0];\n }\n\n const result: AuthStatus = {\n authenticated: credentials.length > 0,\n sources: credentials,\n };\n\n if (preferredSource) {\n result.preferredSource = preferredSource;\n }\n\n if (warnings.length > 0) {\n result.warnings = warnings;\n }\n\n return result;\n}\n\n/**\n * Get credentials for a specific provider\n */\nexport async function getCredentialsForProvider(\n provider: 'anthropic' | 'openai' | 'google',\n config: ExternalAuthConfig = DEFAULT_CONFIG\n): Promise<DetectedCredential | null> {\n const credentials = await detectAllCredentials(config);\n const providerCreds = credentials.filter((c) => c.provider === provider);\n\n if (providerCreds.length === 0) {\n return null;\n }\n\n // Prefer OAuth over API keys\n const found = providerCreds.find((c) => c.authType === 'oauth');\n return found || providerCreds[0] || null;\n}\n\n/**\n * Get environment variables to inject based on detected credentials\n */\nexport async function getAuthEnvironment(\n config: ExternalAuthConfig = DEFAULT_CONFIG\n): Promise<Record<string, string>> {\n const credentials = await detectAllCredentials(config);\n const env: Record<string, string> = {};\n\n // Group by provider and prefer OAuth tokens\n const byProvider = new Map<string, DetectedCredential>();\n\n for (const cred of credentials) {\n const existing = byProvider.get(cred.provider);\n // Prefer OAuth over API keys\n if (!existing || (cred.authType === 'oauth' && existing.authType !== 'oauth')) {\n byProvider.set(cred.provider, cred);\n }\n }\n\n // Map to environment variables\n for (const [provider, cred] of byProvider) {\n if (!cred.value) continue;\n\n switch (provider) {\n case 'anthropic':\n // For OAuth tokens, we use ANTHROPIC_AUTH_TOKEN\n // For API keys, we use ANTHROPIC_API_KEY\n if (cred.authType === 'oauth') {\n env['ANTHROPIC_AUTH_TOKEN'] = cred.value;\n } else {\n env['ANTHROPIC_API_KEY'] = cred.value;\n }\n break;\n\n case 'openai':\n if (cred.authType === 'oauth') {\n // OpenAI Codex uses a different auth header for OAuth\n env['OPENAI_AUTH_TOKEN'] = cred.value;\n } else {\n env['OPENAI_API_KEY'] = cred.value;\n }\n break;\n\n case 'google':\n if (cred.authType === 'oauth') {\n env['GOOGLE_AUTH_TOKEN'] = cred.value;\n } else {\n // Prefer GEMINI_API_KEY, fallback to GOOGLE_API_KEY\n if (cred.envVar === 'GOOGLE_API_KEY') {\n env['GOOGLE_API_KEY'] = cred.value;\n } else {\n env['GEMINI_API_KEY'] = cred.value;\n }\n }\n break;\n }\n }\n\n return env;\n}\n\n/**\n * Format auth status for display\n */\nexport function formatAuthStatus(status: AuthStatus): string {\n const lines: string[] = [];\n\n if (!status.authenticated) {\n lines.push('No authentication detected');\n lines.push('');\n lines.push('To authenticate, either:');\n lines.push(' - Log in with Claude Code: claude');\n lines.push(' - Log in with Codex: codex');\n lines.push(' - Log in with Gemini CLI: gemini');\n lines.push(' - Set environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.)');\n return lines.join('\\n');\n }\n\n lines.push('Detected authentication sources:');\n lines.push('');\n\n for (const cred of status.sources) {\n const isPrimary = cred === status.preferredSource;\n const prefix = isPrimary ? '* ' : ' ';\n const authType = cred.authType === 'oauth' ? 'OAuth' : 'API Key';\n\n let line = `${prefix}${cred.source} (${cred.provider}, ${authType})`;\n\n if (cred.accountInfo?.email) {\n line += ` - ${cred.accountInfo.email}`;\n }\n if (cred.accountInfo?.plan) {\n line += ` [${cred.accountInfo.plan}]`;\n }\n if (cred.expiresAt) {\n const expiresIn = Math.round((cred.expiresAt.getTime() - Date.now()) / 1000 / 60);\n if (expiresIn > 0) {\n line += ` (expires in ${expiresIn}m)`;\n } else {\n line += ' (EXPIRED)';\n }\n }\n\n lines.push(line);\n }\n\n if (status.warnings && status.warnings.length > 0) {\n lines.push('');\n lines.push('Warnings:');\n for (const warning of status.warnings) {\n lines.push(` ! ${warning}`);\n }\n }\n\n return lines.join('\\n');\n}\n","/**\n * Logging utilities\n */\n\nimport chalk from 'chalk';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet currentLevel: LogLevel = 'info';\n\nexport function setLogLevel(level: LogLevel): void {\n currentLevel = level;\n}\n\nexport function getLogLevel(): LogLevel {\n return currentLevel;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\n}\n\nexport const logger = {\n debug(message: string, ...args: unknown[]): void {\n if (shouldLog('debug')) {\n console.log(chalk.gray(`[debug] ${message}`), ...args);\n }\n },\n\n info(message: string, ...args: unknown[]): void {\n if (shouldLog('info')) {\n console.log(chalk.blue('ℹ'), message, ...args);\n }\n },\n\n success(message: string, ...args: unknown[]): void {\n if (shouldLog('info')) {\n console.log(chalk.green('✓'), message, ...args);\n }\n },\n\n warn(message: string, ...args: unknown[]): void {\n if (shouldLog('warn')) {\n console.log(chalk.yellow('⚠'), message, ...args);\n }\n },\n\n error(message: string, ...args: unknown[]): void {\n if (shouldLog('error')) {\n console.error(chalk.red('✗'), message, ...args);\n }\n },\n\n // Styled output helpers\n brand(text: string): string {\n return chalk.hex('#818cf8')(text);\n },\n\n dim(text: string): string {\n return chalk.dim(text);\n },\n\n bold(text: string): string {\n return chalk.bold(text);\n },\n\n // Print a header\n header(text: string): void {\n console.log();\n console.log(chalk.bold(text));\n console.log(chalk.dim('─'.repeat(text.length)));\n },\n\n // Print a blank line\n blank(): void {\n console.log();\n },\n};\n","/**\n * Container management utilities\n * Uses devcontainer CLI for container lifecycle\n */\n\nimport { execa, type ExecaError } from 'execa';\nimport which from 'which';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { RapidConfig } from './types.js';\n\nexport interface ContainerStatus {\n exists: boolean;\n running: boolean;\n containerId?: string;\n containerName?: string;\n}\n\nexport interface DevcontainerConfig {\n name?: string;\n image?: string;\n dockerFile?: string;\n build?: {\n dockerfile?: string;\n context?: string;\n };\n [key: string]: unknown;\n}\n\n/**\n * Check if devcontainer CLI is available\n */\nexport async function hasDevcontainerCli(): Promise<boolean> {\n try {\n await which('devcontainer');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if Docker is available\n */\nexport async function hasDocker(): Promise<boolean> {\n try {\n await execa('docker', ['info'], { timeout: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the devcontainer.json path\n */\nexport function getDevcontainerPath(rootDir: string, config?: RapidConfig): string {\n const customPath = config?.container?.devcontainer;\n if (customPath) {\n return join(rootDir, customPath);\n }\n return join(rootDir, '.devcontainer', 'devcontainer.json');\n}\n\n/**\n * Load devcontainer.json\n */\nexport async function loadDevcontainerConfig(\n rootDir: string,\n config?: RapidConfig\n): Promise<DevcontainerConfig | null> {\n try {\n const configPath = getDevcontainerPath(rootDir, config);\n const content = await readFile(configPath, 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\n/**\n * Get container name for a project\n */\nexport function getContainerName(rootDir: string, devcontainerConfig?: DevcontainerConfig): string {\n // Use devcontainer name if available, otherwise derive from directory\n const dirName = rootDir.split('/').pop() || 'rapid';\n const name = devcontainerConfig?.name || dirName;\n // Sanitize for Docker container name\n return `rapid-${name}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n\n/**\n * Check container status using devcontainer labels\n */\nexport async function getContainerStatus(\n rootDir: string,\n _config?: RapidConfig\n): Promise<ContainerStatus> {\n try {\n // Use devcontainer label to find the container (this is how devcontainer CLI tracks containers)\n const result = await execa('docker', [\n 'ps',\n '-a',\n '--filter',\n `label=devcontainer.local_folder=${rootDir}`,\n '--format',\n '{{.ID}}\\t{{.State}}\\t{{.Names}}',\n ]);\n\n const lines = result.stdout.trim().split('\\n').filter(Boolean);\n if (lines.length === 0) {\n return { exists: false, running: false };\n }\n\n const parts = lines[0]?.split('\\t');\n const containerId = parts?.[0];\n const state = parts?.[1];\n const containerName = parts?.[2];\n\n if (!containerId || !containerName) {\n return { exists: false, running: false };\n }\n\n return {\n exists: true,\n running: state === 'running',\n containerId,\n containerName,\n };\n } catch {\n return { exists: false, running: false };\n }\n}\n\n/**\n * Start the dev container using devcontainer CLI\n */\nexport async function startContainer(\n rootDir: string,\n _config?: RapidConfig,\n options: { rebuild?: boolean; quiet?: boolean } = {}\n): Promise<{ success: boolean; containerId?: string; error?: string }> {\n const hasDevCli = await hasDevcontainerCli();\n\n if (!hasDevCli) {\n return {\n success: false,\n error: 'devcontainer CLI not found. Install with: npm install -g @devcontainers/cli',\n };\n }\n\n const hasDockerRunning = await hasDocker();\n if (!hasDockerRunning) {\n return {\n success: false,\n error: 'Docker is not running. Please start Docker Desktop.',\n };\n }\n\n try {\n const args = ['up', '--workspace-folder', rootDir];\n\n if (options.rebuild) {\n args.push('--remove-existing-container');\n }\n\n const result = await execa('devcontainer', args, {\n stdio: options.quiet ? 'pipe' : 'inherit',\n cwd: rootDir,\n });\n\n // Parse the container ID from output\n // devcontainer up outputs JSON with containerId\n if (options.quiet && result.stdout) {\n try {\n const output = JSON.parse(result.stdout);\n return { success: true, containerId: output.containerId };\n } catch {\n return { success: true };\n }\n }\n\n return { success: true };\n } catch (error) {\n const execError = error as ExecaError;\n const stderr = typeof execError.stderr === 'string' ? execError.stderr : undefined;\n return {\n success: false,\n error: stderr || execError.message,\n };\n }\n}\n\n/**\n * Stop the dev container\n */\nexport async function stopContainer(\n rootDir: string,\n config?: RapidConfig,\n options: { remove?: boolean } = {}\n): Promise<{ success: boolean; error?: string }> {\n const status = await getContainerStatus(rootDir, config);\n\n if (!status.exists) {\n return { success: true }; // Nothing to stop\n }\n\n try {\n if (status.running) {\n await execa('docker', ['stop', status.containerId!]);\n }\n\n if (options.remove) {\n await execa('docker', ['rm', status.containerId!]);\n }\n\n return { success: true };\n } catch (error) {\n const execError = error as ExecaError;\n const stderr = typeof execError.stderr === 'string' ? execError.stderr : undefined;\n return {\n success: false,\n error: stderr || execError.message,\n };\n }\n}\n\n/**\n * Execute a command inside the dev container\n */\nexport async function execInContainer(\n rootDir: string,\n command: string[],\n _config?: RapidConfig,\n options: { interactive?: boolean; tty?: boolean; env?: Record<string, string> } = {}\n): Promise<void> {\n const hasDevCli = await hasDevcontainerCli();\n\n if (!hasDevCli) {\n throw new Error('devcontainer CLI not found. Install with: npm install -g @devcontainers/cli');\n }\n\n const args = ['exec', '--workspace-folder', rootDir];\n\n // Add environment variables\n if (options.env) {\n for (const [key, value] of Object.entries(options.env)) {\n args.push('--remote-env', `${key}=${value}`);\n }\n }\n\n // Add the command\n args.push(...command);\n\n await execa('devcontainer', args, {\n stdio: 'inherit',\n cwd: rootDir,\n });\n}\n","/**\n * Secrets management for RAPID\n * Supports 1Password, HashiCorp Vault, and environment variables\n */\n\nimport { spawn } from 'node:child_process';\nimport { readFile, writeFile, access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { SecretsConfig } from './types.js';\nimport { logger } from './logger.js';\n\nexport interface SecretStatus {\n name: string;\n reference: string;\n provider: 'env' | '1password' | 'vault';\n available: boolean;\n error?: string;\n}\n\nexport interface SecretsStatus {\n provider: 'env' | '1password' | 'vault';\n authenticated: boolean;\n authMethod?: 'service-account' | 'user' | 'token';\n secrets: SecretStatus[];\n allAvailable: boolean;\n}\n\nexport interface OpAuthStatus {\n authenticated: boolean;\n method: 'service-account' | 'user' | 'none';\n accountInfo?: string;\n}\n\n/**\n * Execute a command and return stdout\n */\nasync function execCommand(\n command: string,\n args: string[],\n options: { timeout?: number } = {}\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n return new Promise((resolve) => {\n const proc = spawn(command, args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: options.timeout ?? 30000,\n });\n\n let stdout = '';\n let stderr = '';\n\n proc.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n stderr += data.toString();\n });\n\n proc.on('close', (code) => {\n resolve({ stdout: stdout.trim(), stderr: stderr.trim(), exitCode: code ?? 1 });\n });\n\n proc.on('error', (err) => {\n resolve({ stdout: '', stderr: err.message, exitCode: 1 });\n });\n });\n}\n\n/**\n * Check if 1Password CLI is installed\n */\nexport async function hasOpCli(): Promise<boolean> {\n const result = await execCommand('op', ['--version']);\n return result.exitCode === 0;\n}\n\n/**\n * Check if OP_SERVICE_ACCOUNT_TOKEN is set\n */\nexport function hasOpServiceAccountToken(): boolean {\n return !!process.env.OP_SERVICE_ACCOUNT_TOKEN;\n}\n\n/**\n * Check if 1Password CLI is authenticated (via service account or user)\n */\nexport async function isOpAuthenticated(): Promise<boolean> {\n // Service account token takes precedence\n if (hasOpServiceAccountToken()) {\n // Verify the token works by trying to list vaults\n const result = await execCommand('op', ['vault', 'list', '--format=json']);\n return result.exitCode === 0;\n }\n\n // Fall back to user authentication\n const result = await execCommand('op', ['account', 'list']);\n return result.exitCode === 0 && result.stdout.length > 0;\n}\n\n/**\n * Get detailed 1Password authentication status\n */\nexport async function getOpAuthStatus(): Promise<OpAuthStatus> {\n // Check for service account token first\n if (hasOpServiceAccountToken()) {\n const result = await execCommand('op', ['vault', 'list', '--format=json']);\n if (result.exitCode === 0) {\n return {\n authenticated: true,\n method: 'service-account',\n accountInfo: 'Service Account',\n };\n }\n return {\n authenticated: false,\n method: 'none',\n accountInfo: 'Invalid service account token',\n };\n }\n\n // Check for user authentication\n const result = await execCommand('op', ['account', 'list', '--format=json']);\n if (result.exitCode === 0 && result.stdout.length > 0) {\n try {\n const accounts = JSON.parse(result.stdout);\n if (accounts.length > 0) {\n return {\n authenticated: true,\n method: 'user',\n accountInfo: accounts[0].email || accounts[0].url,\n };\n }\n } catch {\n // Parse error, but command succeeded\n return {\n authenticated: true,\n method: 'user',\n };\n }\n }\n\n return {\n authenticated: false,\n method: 'none',\n };\n}\n\n/**\n * Check if HashiCorp Vault CLI is installed\n */\nexport async function hasVaultCli(): Promise<boolean> {\n const result = await execCommand('vault', ['--version']);\n return result.exitCode === 0;\n}\n\n/**\n * Check if HashiCorp Vault is authenticated\n */\nexport async function isVaultAuthenticated(): Promise<boolean> {\n const result = await execCommand('vault', ['token', 'lookup']);\n return result.exitCode === 0;\n}\n\n/**\n * Read a secret from 1Password\n * @param reference - 1Password reference (e.g., \"op://vault/item/field\")\n */\nexport async function readOpSecret(reference: string): Promise<string | null> {\n const result = await execCommand('op', ['read', reference]);\n if (result.exitCode !== 0) {\n return null;\n }\n return result.stdout;\n}\n\n/**\n * Read a secret from HashiCorp Vault\n * @param path - Vault path (e.g., \"secret/data/myproject\")\n * @param field - Field name within the secret\n */\nexport async function readVaultSecret(path: string, field: string): Promise<string | null> {\n const result = await execCommand('vault', ['kv', 'get', '-field', field, path]);\n if (result.exitCode !== 0) {\n return null;\n }\n return result.stdout;\n}\n\n/**\n * Verify a single secret is accessible\n */\nexport async function verifySecret(\n name: string,\n reference: string,\n provider: 'env' | '1password' | 'vault',\n config?: SecretsConfig\n): Promise<SecretStatus> {\n const status: SecretStatus = {\n name,\n reference,\n provider,\n available: false,\n };\n\n try {\n switch (provider) {\n case 'env': {\n const value = process.env[name];\n status.available = !!value && value.length > 0;\n if (!status.available) {\n status.error = 'Environment variable not set';\n }\n break;\n }\n\n case '1password': {\n // Reference should be in format op://vault/item/field\n const value = await readOpSecret(reference);\n status.available = value !== null;\n if (!status.available) {\n status.error = 'Secret not found in 1Password';\n }\n break;\n }\n\n case 'vault': {\n // Parse path and field from reference\n const field = reference.split('/').pop() || 'value';\n const vaultPath = reference.includes('/')\n ? reference.substring(0, reference.lastIndexOf('/'))\n : config?.vault || 'secret/data/default';\n\n const value = await readVaultSecret(vaultPath, field);\n status.available = value !== null;\n if (!status.available) {\n status.error = 'Secret not found in Vault';\n }\n break;\n }\n }\n } catch (error) {\n status.error = error instanceof Error ? error.message : String(error);\n status.available = false;\n }\n\n return status;\n}\n\n/**\n * Verify all secrets in configuration\n */\nexport async function verifySecrets(config: SecretsConfig): Promise<SecretsStatus> {\n const provider = config.provider || 'env';\n let authenticated = true;\n\n // Check authentication status for provider\n switch (provider) {\n case '1password':\n authenticated = await isOpAuthenticated();\n break;\n case 'vault':\n authenticated = await isVaultAuthenticated();\n break;\n case 'env':\n authenticated = true;\n break;\n }\n\n const secrets: SecretStatus[] = [];\n\n if (config.items) {\n for (const [name, reference] of Object.entries(config.items)) {\n const status = await verifySecret(name, reference, provider, config);\n secrets.push(status);\n }\n }\n\n const allAvailable = secrets.length === 0 || secrets.every((s) => s.available);\n\n return {\n provider,\n authenticated,\n secrets,\n allAvailable,\n };\n}\n\n/**\n * Load all secrets into environment\n */\nexport async function loadSecrets(config: SecretsConfig): Promise<Record<string, string>> {\n const provider = config.provider || 'env';\n const secrets: Record<string, string> = {};\n\n if (!config.items) {\n return secrets;\n }\n\n for (const [name, reference] of Object.entries(config.items)) {\n try {\n let value: string | null = null;\n\n switch (provider) {\n case 'env':\n value = process.env[name] || null;\n break;\n\n case '1password':\n value = await readOpSecret(reference);\n break;\n\n case 'vault': {\n const field = reference.split('/').pop() || 'value';\n const path = reference.substring(0, reference.lastIndexOf('/')) || config.vault || '';\n value = await readVaultSecret(path, field);\n break;\n }\n }\n\n if (value) {\n secrets[name] = value;\n }\n } catch (error) {\n logger.debug(`Failed to load secret ${name}: ${error}`);\n }\n }\n\n return secrets;\n}\n\n/**\n * Generate .envrc file from secrets configuration\n */\nexport function generateEnvrc(config: SecretsConfig): string {\n const provider = config.provider || 'env';\n const lines: string[] = [\n '# .envrc - RAPID project secrets',\n '# This file is safe to commit - it contains NO secrets, only references',\n '#',\n `# Provider: ${provider}`,\n `# Generated by: rapid secrets generate`,\n '',\n ];\n\n if (!config.items || Object.keys(config.items).length === 0) {\n lines.push('# No secrets configured in rapid.json');\n return lines.join('\\n');\n }\n\n switch (provider) {\n case '1password':\n lines.push('# Secrets loaded from 1Password');\n lines.push('# Requires: 1Password CLI (op) installed and authenticated');\n lines.push('');\n for (const [name, reference] of Object.entries(config.items)) {\n lines.push(`export ${name}=$(op read \"${reference}\")`);\n }\n break;\n\n case 'vault':\n lines.push('# Secrets loaded from HashiCorp Vault');\n lines.push('# Requires: Vault CLI installed and authenticated');\n lines.push('');\n if (config.address) {\n lines.push(`export VAULT_ADDR=\"${config.address}\"`);\n lines.push('');\n }\n for (const [name, reference] of Object.entries(config.items)) {\n const path = config.vault || 'secret/data/default';\n lines.push(`export ${name}=$(vault kv get -field=${reference} ${path})`);\n }\n break;\n\n case 'env':\n lines.push('# WARNING: env provider expects secrets to be set manually');\n lines.push('# Consider using 1password or vault for better security');\n lines.push('');\n lines.push('# Uncomment and set values (DO NOT commit actual values!)');\n for (const name of Object.keys(config.items)) {\n lines.push(`# export ${name}=\"your-value-here\"`);\n }\n break;\n }\n\n // Add .env.local loading if configured\n if (config.envrc?.includeLocal !== false) {\n lines.push('');\n lines.push('# Load local overrides if present');\n lines.push('[[ -f .env.local ]] && source_env .env.local');\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n\n/**\n * Write .envrc file to project directory\n */\nexport async function writeEnvrc(rootDir: string, config: SecretsConfig): Promise<string> {\n const envrcPath = config.envrc?.path || '.envrc';\n const fullPath = join(rootDir, envrcPath);\n const content = generateEnvrc(config);\n\n await writeFile(fullPath, content);\n return fullPath;\n}\n\n/**\n * Check if .envrc exists in project\n */\nexport async function hasEnvrc(rootDir: string, config?: SecretsConfig): Promise<boolean> {\n const envrcPath = config?.envrc?.path || '.envrc';\n const fullPath = join(rootDir, envrcPath);\n\n try {\n await access(fullPath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Read existing .envrc content\n */\nexport async function readEnvrc(rootDir: string, config?: SecretsConfig): Promise<string | null> {\n const envrcPath = config?.envrc?.path || '.envrc';\n const fullPath = join(rootDir, envrcPath);\n\n try {\n const content = await readFile(fullPath, 'utf-8');\n return content;\n } catch {\n return null;\n }\n}\n\n/**\n * Get a summary of provider requirements\n */\nexport function getProviderInfo(provider: 'env' | '1password' | 'vault'): {\n name: string;\n cliRequired: string | null;\n authCommand: string | null;\n installUrl: string | null;\n} {\n switch (provider) {\n case '1password':\n return {\n name: '1Password',\n cliRequired: 'op',\n authCommand: 'eval $(op signin)',\n installUrl: 'https://developer.1password.com/docs/cli/get-started/',\n };\n case 'vault':\n return {\n name: 'HashiCorp Vault',\n cliRequired: 'vault',\n authCommand: 'vault login',\n installUrl: 'https://developer.hashicorp.com/vault/docs/install',\n };\n case 'env':\n return {\n name: 'Environment Variables',\n cliRequired: null,\n authCommand: null,\n installUrl: null,\n };\n }\n}\n"],"mappings":";AAIA,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,SAAS,eAAe;AAGjC,IAAM,cAAc;AACpB,IAAM,eAAe,CAAC,cAAc,qBAAqB,YAAY,eAAe;AAWpF,eAAsB,WAAW,KAA4C;AAC3E,QAAM,WAAW,YAAY,aAAa;AAAA,IACxC,cAAc;AAAA,IACd,SAAS;AAAA,MACP,SAAS,OAAO,aAAa;AAC3B,cAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,eAAO,KAAK,MAAM,OAAO;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,SAAS,MAAM,SAAS,OAAO,GAAG;AAExC,MAAI,CAAC,UAAU,OAAO,SAAS;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,SAAS,QAAQ,OAAO,QAAQ;AAAA,EAClC;AACF;AAKA,eAAsB,mBAAmB,UAAyC;AAChF,QAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,QAAM,SAAS,KAAK,MAAM,OAAO;AAEjC,SAAO;AAAA,IACL;AAAA,IACA,UAAU,QAAQ,QAAQ;AAAA,IAC1B,SAAS,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EACpC;AACF;AAKO,SAAS,mBAAgC;AAC9C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA,QACT,QAAQ;AAAA,UACN,KAAK;AAAA,UACL,iBAAiB;AAAA,UACjB,SAAS,CAAC,mBAAmB;AAAA,QAC/B;AAAA,QACA,UAAU;AAAA,UACR,KAAK;AAAA,UACL,iBAAiB;AAAA,UACjB,SAAS,CAAC,mBAAmB;AAAA,QAC/B;AAAA,QACA,OAAO;AAAA,UACL,KAAK;AAAA,UACL,iBAAiB;AAAA,UACjB,SAAS,CAAC,mBAAmB;AAAA,UAC7B,MAAM,CAAC,WAAW,4BAA4B;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,UAAU;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,MACP,OAAO,CAAC,WAAW;AAAA,MACnB,MAAM,CAAC,OAAO;AAAA,MACd,oBAAoB;AAAA,IACtB;AAAA,EACF;AACF;AAKO,SAAS,kBAAkB,QAA2C;AAC3E,QAAM,WAAW,iBAAiB;AAElC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ;AAAA,MACN,GAAG,SAAS;AAAA,MACZ,GAAG,OAAO;AAAA,MACV,WAAW;AAAA,QACT,GAAG,SAAS,OAAO;AAAA,QACnB,GAAG,OAAO,QAAQ;AAAA,MACpB;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,GAAG,SAAS;AAAA,MACZ,GAAG,OAAO;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,MACP,GAAG,SAAS;AAAA,MACZ,GAAG,OAAO;AAAA,IACZ;AAAA,EACF;AACF;;;ACvHA,SAAS,aAAa;AACtB,OAAO,WAAW;;;ACKlB,SAAS,YAAAA,WAAU,cAAc;AACjC,SAAS,eAAe;AACxB,SAAS,YAAY;;;ACRrB,OAAO,WAAW;AAIlB,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,IAAI,eAAyB;AAEtB,SAAS,YAAY,OAAuB;AACjD,iBAAe;AACjB;AAEO,SAAS,cAAwB;AACtC,SAAO;AACT;AAEA,SAAS,UAAU,OAA0B;AAC3C,SAAO,WAAW,KAAK,KAAK,WAAW,YAAY;AACrD;AAEO,IAAM,SAAS;AAAA,EACpB,MAAM,YAAoB,MAAuB;AAC/C,QAAI,UAAU,OAAO,GAAG;AACtB,cAAQ,IAAI,MAAM,KAAK,WAAW,OAAO,EAAE,GAAG,GAAG,IAAI;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,KAAK,YAAoB,MAAuB;AAC9C,QAAI,UAAU,MAAM,GAAG;AACrB,cAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,SAAS,GAAG,IAAI;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,QAAQ,YAAoB,MAAuB;AACjD,QAAI,UAAU,MAAM,GAAG;AACrB,cAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,SAAS,GAAG,IAAI;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,KAAK,YAAoB,MAAuB;AAC9C,QAAI,UAAU,MAAM,GAAG;AACrB,cAAQ,IAAI,MAAM,OAAO,QAAG,GAAG,SAAS,GAAG,IAAI;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,MAAM,YAAoB,MAAuB;AAC/C,QAAI,UAAU,OAAO,GAAG;AACtB,cAAQ,MAAM,MAAM,IAAI,QAAG,GAAG,SAAS,GAAG,IAAI;AAAA,IAChD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,MAAsB;AAC1B,WAAO,MAAM,IAAI,SAAS,EAAE,IAAI;AAAA,EAClC;AAAA,EAEA,IAAI,MAAsB;AACxB,WAAO,MAAM,IAAI,IAAI;AAAA,EACvB;AAAA,EAEA,KAAK,MAAsB;AACzB,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAAA;AAAA,EAGA,OAAO,MAAoB;AACzB,YAAQ,IAAI;AACZ,YAAQ,IAAI,MAAM,KAAK,IAAI,CAAC;AAC5B,YAAQ,IAAI,MAAM,IAAI,SAAI,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,EAChD;AAAA;AAAA,EAGA,QAAc;AACZ,YAAQ,IAAI;AAAA,EACd;AACF;;;ADjEA,IAAM,iBAAqC;AAAA,EACzC,SAAS;AAAA,EACT,SAAS,CAAC,eAAe,SAAS,cAAc,SAAS,KAAK;AAChE;AAKA,eAAe,WAAW,MAAgC;AACxD,MAAI;AACF,UAAM,OAAO,IAAI;AACjB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,eAAe,aAAgB,MAAiC;AAC9D,MAAI;AACF,UAAM,UAAU,MAAMC,UAAS,MAAM,OAAO;AAC5C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA2BA,eAAsB,uBAA2D;AAC/E,QAAM,OAAO,QAAQ;AACrB,QAAM,aAAa,KAAK,MAAM,cAAc;AAE5C,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,MAAM,aAA+B,UAAU;AAC9D,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,OAAO,gBAAgB,OAAO;AAC5C,MAAI,OAAO,aAAa;AACtB,UAAM,YAAY,MAAM,YAAY,IAAI,KAAK,MAAM,SAAS,IAAI;AAGhE,QAAI,aAAa,YAAY,oBAAI,KAAK,GAAG;AACvC,aAAO,MAAM,iCAAiC;AAC9C,aAAO;AAAA,IACT;AAEA,UAAM,OAA2B;AAAA,MAC/B,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAO,MAAM;AAAA,MACb;AAAA,IACF;AAEA,QAAI,WAAW;AACb,WAAK,YAAY;AAAA,IACnB;AAEA,UAAM,cAIF,CAAC;AAEL,QAAI,OAAO,cAAc,cAAc;AACrC,kBAAY,QAAQ,OAAO,aAAa;AAAA,IAC1C;AACA,QAAI,OAAO,cAAc,kBAAkB;AACzC,kBAAY,eAAe,OAAO,aAAa;AAAA,IACjD;AACA,QAAI,OAAO,cAAc,UAAU;AACjC,kBAAY,OAAO,OAAO,aAAa;AAAA,IACzC;AAEA,QAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GAAG;AACvC,WAAK,cAAc;AAAA,IACrB;AAEA,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,QAAQ;AACV,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAsBA,eAAsB,kBAAsD;AAC1E,QAAM,OAAO,QAAQ;AACrB,QAAM,aAAa,KAAK,MAAM,UAAU,WAAW;AAEnD,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,MAAM,aAA8B,UAAU;AAC7D,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,SAAS,aAAa;AAC/B,UAAM,YAAY,OAAO,QAAQ,YAAY,IAAI,KAAK,OAAO,QAAQ,SAAS,IAAI;AAGlF,QAAI,aAAa,YAAY,oBAAI,KAAK,GAAG;AACvC,aAAO,MAAM,mCAAmC;AAChD,aAAO;AAAA,IACT;AAEA,UAAM,OAA2B;AAAA,MAC/B,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAO,OAAO,QAAQ;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,WAAW;AACb,WAAK,YAAY;AAAA,IACnB;AAEA,UAAM,cAIF,CAAC;AAEL,QAAI,OAAO,QAAQ,OAAO;AACxB,kBAAY,QAAQ,OAAO,QAAQ;AAAA,IACrC;AACA,QAAI,OAAO,QAAQ,aAAa;AAC9B,kBAAY,eAAe,OAAO,QAAQ;AAAA,IAC5C;AAEA,QAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GAAG;AACvC,WAAK,cAAc;AAAA,IACrB;AAEA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,KAAK,QAAQ;AACtB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAO,OAAO,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,QAAQ;AACV,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAqBA,eAAsB,mBAAuD;AAC3E,QAAM,OAAO,QAAQ;AACrB,QAAM,eAAe,KAAK,MAAM,WAAW,eAAe;AAG1D,MAAI,MAAM,WAAW,YAAY,GAAG;AAClC,UAAM,WAAW,MAAM,aAA6B,YAAY;AAChE,QAAI,UAAU,MAAM,OAAO,aAAa;AACtC,YAAM,QAAQ,SAAS,KAAK;AAC5B,YAAM,YAAY,MAAM,YAAY,IAAI,KAAK,MAAM,SAAS,IAAI;AAEhE,UAAI,aAAa,YAAY,oBAAI,KAAK,GAAG;AACvC,eAAO,MAAM,gCAAgC;AAAA,MAC/C,OAAO;AACL,cAAM,OAA2B;AAAA,UAC/B,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,UAAU;AAAA,UACV,OAAO,MAAM;AAAA,UACb,YAAY;AAAA,QACd;AAEA,YAAI,WAAW;AACb,eAAK,YAAY;AAAA,QACnB;AAEA,cAAM,cAIF,CAAC;AAEL,YAAI,MAAM,OAAO;AACf,sBAAY,QAAQ,MAAM;AAAA,QAC5B;AACA,YAAI,SAAS,oBAAoB;AAC/B,sBAAY,eAAe,SAAS;AAAA,QACtC;AAEA,YAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GAAG;AACvC,eAAK,cAAc;AAAA,QACrB;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,WAAW;AACb,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,WAAW;AACb,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAUA,eAAsB,kBAAiD;AACrE,QAAM,cAAoC,CAAC;AAG3C,QAAM,eAAe,QAAQ,IAAI;AACjC,MAAI,cAAc;AAChB,gBAAY,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,WAAW;AACb,gBAAY,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,WAAW;AACb,gBAAY,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AASA,eAAsB,gBAA+C;AACnE,QAAM,cAAoC,CAAC;AAE3C,QAAM,cAGD;AAAA,IACH,EAAE,QAAQ,qBAAqB,UAAU,YAAY;AAAA,IACrD,EAAE,QAAQ,kBAAkB,UAAU,SAAS;AAAA,IAC/C,EAAE,QAAQ,kBAAkB,UAAU,SAAS;AAAA,IAC/C,EAAE,QAAQ,kBAAkB,UAAU,SAAS;AAAA,EACjD;AAEA,aAAW,EAAE,QAAQ,SAAS,KAAK,aAAa;AAC9C,UAAM,QAAQ,QAAQ,IAAI,MAAM;AAChC,QAAI,OAAO;AACT,kBAAY,KAAK;AAAA,QACf,QAAQ;AAAA,QACR;AAAA,QACA,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AASA,eAAsB,qBACpB,SAA6B,gBACE;AAC/B,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,UAAU,OAAO,WAAW,eAAe;AACjD,QAAM,cAAoC,CAAC;AAC3C,QAAM,aAAa,oBAAI,IAAY;AAEnC,aAAW,UAAU,SAAS;AAC5B,QAAI;AACF,UAAI,WAA6D;AAEjE,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,qBAAW,MAAM,qBAAqB;AACtC;AAAA,QACF,KAAK;AACH,qBAAW,MAAM,gBAAgB;AACjC;AAAA,QACF,KAAK;AACH,qBAAW,MAAM,iBAAiB;AAClC;AAAA,QACF,KAAK;AACH,qBAAW,MAAM,gBAAgB;AACjC;AAAA,QACF,KAAK;AACH,qBAAW,MAAM,cAAc;AAC/B;AAAA,MACJ;AAEA,UAAI,UAAU;AACZ,cAAM,QAAQ,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;AAC5D,mBAAW,QAAQ,OAAO;AAExB,gBAAM,MAAM,KAAK,SAAS,KAAK,UAAU;AACzC,cAAI,OAAO,CAAC,WAAW,IAAI,GAAG,GAAG;AAC/B,uBAAW,IAAI,GAAG;AAClB,wBAAY,KAAK,IAAI;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO,MAAM,mBAAmB,MAAM,iBAAiB,KAAK;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AACT;AAKA,eAAsB,cACpB,SAA6B,gBACR;AACrB,QAAM,cAAc,MAAM,qBAAqB,MAAM;AACrD,QAAM,WAAqB,CAAC;AAG5B,aAAW,QAAQ,aAAa;AAC9B,QAAI,KAAK,aAAa,KAAK,YAAY,oBAAI,KAAK,GAAG;AACjD,eAAS,KAAK,GAAG,KAAK,MAAM,mDAAmD;AAAA,IACjF;AAAA,EACF;AAGA,MAAI;AACJ,MAAI,OAAO,cAAc;AACvB,sBAAkB,YAAY,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO,YAAY;AAAA,EAC5E;AAGA,MAAI,CAAC,mBAAmB,YAAY,SAAS,GAAG;AAC9C,sBAAkB,YAAY,KAAK,CAAC,MAAM,EAAE,aAAa,OAAO,KAAK,YAAY,CAAC;AAAA,EACpF;AAEA,QAAM,SAAqB;AAAA,IACzB,eAAe,YAAY,SAAS;AAAA,IACpC,SAAS;AAAA,EACX;AAEA,MAAI,iBAAiB;AACnB,WAAO,kBAAkB;AAAA,EAC3B;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO,WAAW;AAAA,EACpB;AAEA,SAAO;AACT;AAKA,eAAsB,0BACpB,UACA,SAA6B,gBACO;AACpC,QAAM,cAAc,MAAM,qBAAqB,MAAM;AACrD,QAAM,gBAAgB,YAAY,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ;AAEvE,MAAI,cAAc,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,cAAc,KAAK,CAAC,MAAM,EAAE,aAAa,OAAO;AAC9D,SAAO,SAAS,cAAc,CAAC,KAAK;AACtC;AAKA,eAAsB,mBACpB,SAA6B,gBACI;AACjC,QAAM,cAAc,MAAM,qBAAqB,MAAM;AACrD,QAAM,MAA8B,CAAC;AAGrC,QAAM,aAAa,oBAAI,IAAgC;AAEvD,aAAW,QAAQ,aAAa;AAC9B,UAAM,WAAW,WAAW,IAAI,KAAK,QAAQ;AAE7C,QAAI,CAAC,YAAa,KAAK,aAAa,WAAW,SAAS,aAAa,SAAU;AAC7E,iBAAW,IAAI,KAAK,UAAU,IAAI;AAAA,IACpC;AAAA,EACF;AAGA,aAAW,CAAC,UAAU,IAAI,KAAK,YAAY;AACzC,QAAI,CAAC,KAAK,MAAO;AAEjB,YAAQ,UAAU;AAAA,MAChB,KAAK;AAGH,YAAI,KAAK,aAAa,SAAS;AAC7B,cAAI,sBAAsB,IAAI,KAAK;AAAA,QACrC,OAAO;AACL,cAAI,mBAAmB,IAAI,KAAK;AAAA,QAClC;AACA;AAAA,MAEF,KAAK;AACH,YAAI,KAAK,aAAa,SAAS;AAE7B,cAAI,mBAAmB,IAAI,KAAK;AAAA,QAClC,OAAO;AACL,cAAI,gBAAgB,IAAI,KAAK;AAAA,QAC/B;AACA;AAAA,MAEF,KAAK;AACH,YAAI,KAAK,aAAa,SAAS;AAC7B,cAAI,mBAAmB,IAAI,KAAK;AAAA,QAClC,OAAO;AAEL,cAAI,KAAK,WAAW,kBAAkB;AACpC,gBAAI,gBAAgB,IAAI,KAAK;AAAA,UAC/B,OAAO;AACL,gBAAI,gBAAgB,IAAI,KAAK;AAAA,UAC/B;AAAA,QACF;AACA;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,iBAAiB,QAA4B;AAC3D,QAAM,QAAkB,CAAC;AAEzB,MAAI,CAAC,OAAO,eAAe;AACzB,UAAM,KAAK,4BAA4B;AACvC,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,0BAA0B;AACrC,UAAM,KAAK,qCAAqC;AAChD,UAAM,KAAK,8BAA8B;AACzC,UAAM,KAAK,oCAAoC;AAC/C,UAAM,KAAK,yEAAyE;AACpF,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,QAAM,KAAK,kCAAkC;AAC7C,QAAM,KAAK,EAAE;AAEb,aAAW,QAAQ,OAAO,SAAS;AACjC,UAAM,YAAY,SAAS,OAAO;AAClC,UAAM,SAAS,YAAY,OAAO;AAClC,UAAM,WAAW,KAAK,aAAa,UAAU,UAAU;AAEvD,QAAI,OAAO,GAAG,MAAM,GAAG,KAAK,MAAM,KAAK,KAAK,QAAQ,KAAK,QAAQ;AAEjE,QAAI,KAAK,aAAa,OAAO;AAC3B,cAAQ,MAAM,KAAK,YAAY,KAAK;AAAA,IACtC;AACA,QAAI,KAAK,aAAa,MAAM;AAC1B,cAAQ,KAAK,KAAK,YAAY,IAAI;AAAA,IACpC;AACA,QAAI,KAAK,WAAW;AAClB,YAAM,YAAY,KAAK,OAAO,KAAK,UAAU,QAAQ,IAAI,KAAK,IAAI,KAAK,MAAO,EAAE;AAChF,UAAI,YAAY,GAAG;AACjB,gBAAQ,gBAAgB,SAAS;AAAA,MACnC,OAAO;AACL,gBAAQ;AAAA,MACV;AAAA,IACF;AAEA,UAAM,KAAK,IAAI;AAAA,EACjB;AAEA,MAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;AACjD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,WAAW;AACtB,eAAW,WAAW,OAAO,UAAU;AACrC,YAAM,KAAK,OAAO,OAAO,EAAE;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AD9oBA,eAAsB,oBAAoB,OAA8C;AACtF,MAAI;AACF,UAAM,UAAU,MAAM,MAAM,MAAM,GAAG;AAGrC,QAAI;AACJ,QAAI;AACF,YAAM,SAAS,MAAM,MAAM,MAAM,KAAK,CAAC,WAAW,GAAG,EAAE,SAAS,IAAK,CAAC;AACtE,gBAAU,OAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC;AAAA,IAC9C,QAAQ;AAAA,IAER;AAEA,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA,GAAI,YAAY,UAAa,EAAE,QAAQ;AAAA,IACzC;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,WAAW;AAAA,IACb;AAAA,EACF;AACF;AAKA,eAAsB,eAAe,QAA6C;AAChF,QAAM,UAAyB,CAAC;AAEhC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,OAAO,SAAS,GAAG;AACnE,UAAM,SAAS,MAAM,oBAAoB,KAAK;AAC9C,YAAQ,KAAK;AAAA,MACX,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAKO,SAAS,gBAAgB,QAA6C;AAC3E,QAAM,cAAc,OAAO,OAAO;AAClC,SAAO,OAAO,OAAO,UAAU,WAAW,KAAK;AACjD;AAKO,SAAS,SAAS,QAAqB,MAAsC;AAClF,SAAO,OAAO,OAAO,UAAU,IAAI,KAAK;AAC1C;AAKA,eAAsB,YACpB,OACA,UAMI,CAAC,GACU;AACf,QAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;AAGvC,MAAI,UAAkC,CAAC;AACvC,MAAI,QAAQ,oBAAoB,OAAO;AACrC,cAAU,MAAM,mBAAmB,QAAQ,kBAAkB;AAAA,EAC/D;AAEA,QAAM,MAAM,MAAM,KAAK,MAAM;AAAA,IAC3B;AAAA,IACA,KAAK;AAAA,MACH,GAAG,QAAQ;AAAA,MACX,GAAG;AAAA,MACH,GAAG,QAAQ;AAAA;AAAA,IACb;AAAA,IACA,OAAO,QAAQ,SAAS;AAAA,EAC1B,CAAC;AACH;;;AGjGA,SAAS,SAAAC,cAA8B;AACvC,OAAOC,YAAW;AAClB,SAAS,YAAAC,iBAAgB;AACzB,SAAS,QAAAC,aAAY;AAwBrB,eAAsB,qBAAuC;AAC3D,MAAI;AACF,UAAMF,OAAM,cAAc;AAC1B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,YAA8B;AAClD,MAAI;AACF,UAAMD,OAAM,UAAU,CAAC,MAAM,GAAG,EAAE,SAAS,IAAK,CAAC;AACjD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,oBAAoB,SAAiB,QAA8B;AACjF,QAAM,aAAa,QAAQ,WAAW;AACtC,MAAI,YAAY;AACd,WAAOG,MAAK,SAAS,UAAU;AAAA,EACjC;AACA,SAAOA,MAAK,SAAS,iBAAiB,mBAAmB;AAC3D;AAKA,eAAsB,uBACpB,SACA,QACoC;AACpC,MAAI;AACF,UAAM,aAAa,oBAAoB,SAAS,MAAM;AACtD,UAAM,UAAU,MAAMD,UAAS,YAAY,OAAO;AAClD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,iBAAiB,SAAiB,oBAAiD;AAEjG,QAAM,UAAU,QAAQ,MAAM,GAAG,EAAE,IAAI,KAAK;AAC5C,QAAM,OAAO,oBAAoB,QAAQ;AAEzC,SAAO,SAAS,IAAI,GAAG,YAAY,EAAE,QAAQ,eAAe,GAAG;AACjE;AAKA,eAAsB,mBACpB,SACA,SAC0B;AAC1B,MAAI;AAEF,UAAM,SAAS,MAAMF,OAAM,UAAU;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA,mCAAmC,OAAO;AAAA,MAC1C;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,QAAQ,OAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAC7D,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO,EAAE,QAAQ,OAAO,SAAS,MAAM;AAAA,IACzC;AAEA,UAAM,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAI;AAClC,UAAM,cAAc,QAAQ,CAAC;AAC7B,UAAM,QAAQ,QAAQ,CAAC;AACvB,UAAM,gBAAgB,QAAQ,CAAC;AAE/B,QAAI,CAAC,eAAe,CAAC,eAAe;AAClC,aAAO,EAAE,QAAQ,OAAO,SAAS,MAAM;AAAA,IACzC;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,QAAQ,OAAO,SAAS,MAAM;AAAA,EACzC;AACF;AAKA,eAAsB,eACpB,SACA,SACA,UAAkD,CAAC,GACkB;AACrE,QAAM,YAAY,MAAM,mBAAmB;AAE3C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,mBAAmB,MAAM,UAAU;AACzC,MAAI,CAAC,kBAAkB;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI;AACF,UAAM,OAAO,CAAC,MAAM,sBAAsB,OAAO;AAEjD,QAAI,QAAQ,SAAS;AACnB,WAAK,KAAK,6BAA6B;AAAA,IACzC;AAEA,UAAM,SAAS,MAAMA,OAAM,gBAAgB,MAAM;AAAA,MAC/C,OAAO,QAAQ,QAAQ,SAAS;AAAA,MAChC,KAAK;AAAA,IACP,CAAC;AAID,QAAI,QAAQ,SAAS,OAAO,QAAQ;AAClC,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,OAAO,MAAM;AACvC,eAAO,EAAE,SAAS,MAAM,aAAa,OAAO,YAAY;AAAA,MAC1D,QAAQ;AACN,eAAO,EAAE,SAAS,KAAK;AAAA,MACzB;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB,SAAS,OAAO;AACd,UAAM,YAAY;AAClB,UAAM,SAAS,OAAO,UAAU,WAAW,WAAW,UAAU,SAAS;AACzE,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,UAAU,UAAU;AAAA,IAC7B;AAAA,EACF;AACF;AAKA,eAAsB,cACpB,SACA,QACA,UAAgC,CAAC,GACc;AAC/C,QAAM,SAAS,MAAM,mBAAmB,SAAS,MAAM;AAEvD,MAAI,CAAC,OAAO,QAAQ;AAClB,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AAEA,MAAI;AACF,QAAI,OAAO,SAAS;AAClB,YAAMA,OAAM,UAAU,CAAC,QAAQ,OAAO,WAAY,CAAC;AAAA,IACrD;AAEA,QAAI,QAAQ,QAAQ;AAClB,YAAMA,OAAM,UAAU,CAAC,MAAM,OAAO,WAAY,CAAC;AAAA,IACnD;AAEA,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB,SAAS,OAAO;AACd,UAAM,YAAY;AAClB,UAAM,SAAS,OAAO,UAAU,WAAW,WAAW,UAAU,SAAS;AACzE,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,UAAU,UAAU;AAAA,IAC7B;AAAA,EACF;AACF;AAKA,eAAsB,gBACpB,SACA,SACA,SACA,UAAkF,CAAC,GACpE;AACf,QAAM,YAAY,MAAM,mBAAmB;AAE3C,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,6EAA6E;AAAA,EAC/F;AAEA,QAAM,OAAO,CAAC,QAAQ,sBAAsB,OAAO;AAGnD,MAAI,QAAQ,KAAK;AACf,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG,GAAG;AACtD,WAAK,KAAK,gBAAgB,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,IAC7C;AAAA,EACF;AAGA,OAAK,KAAK,GAAG,OAAO;AAEpB,QAAMA,OAAM,gBAAgB,MAAM;AAAA,IAChC,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACH;;;AC7PA,SAAS,aAAa;AACtB,SAAS,YAAAI,WAAU,WAAW,UAAAC,eAAc;AAC5C,SAAS,QAAAC,aAAY;AA6BrB,eAAe,YACb,SACA,MACA,UAAgC,CAAC,GAC8B;AAC/D,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,UAAM,OAAO,MAAM,SAAS,MAAM;AAAA,MAChC,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,MAC9B,SAAS,QAAQ,WAAW;AAAA,IAC9B,CAAC;AAED,QAAI,SAAS;AACb,QAAI,SAAS;AAEb,SAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAChC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,SAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAChC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,SAAS;AACzB,MAAAA,SAAQ,EAAE,QAAQ,OAAO,KAAK,GAAG,QAAQ,OAAO,KAAK,GAAG,UAAU,QAAQ,EAAE,CAAC;AAAA,IAC/E,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,MAAAA,SAAQ,EAAE,QAAQ,IAAI,QAAQ,IAAI,SAAS,UAAU,EAAE,CAAC;AAAA,IAC1D,CAAC;AAAA,EACH,CAAC;AACH;AAKA,eAAsB,WAA6B;AACjD,QAAM,SAAS,MAAM,YAAY,MAAM,CAAC,WAAW,CAAC;AACpD,SAAO,OAAO,aAAa;AAC7B;AAKO,SAAS,2BAAoC;AAClD,SAAO,CAAC,CAAC,QAAQ,IAAI;AACvB;AAKA,eAAsB,oBAAsC;AAE1D,MAAI,yBAAyB,GAAG;AAE9B,UAAMC,UAAS,MAAM,YAAY,MAAM,CAAC,SAAS,QAAQ,eAAe,CAAC;AACzE,WAAOA,QAAO,aAAa;AAAA,EAC7B;AAGA,QAAM,SAAS,MAAM,YAAY,MAAM,CAAC,WAAW,MAAM,CAAC;AAC1D,SAAO,OAAO,aAAa,KAAK,OAAO,OAAO,SAAS;AACzD;AAKA,eAAsB,kBAAyC;AAE7D,MAAI,yBAAyB,GAAG;AAC9B,UAAMA,UAAS,MAAM,YAAY,MAAM,CAAC,SAAS,QAAQ,eAAe,CAAC;AACzE,QAAIA,QAAO,aAAa,GAAG;AACzB,aAAO;AAAA,QACL,eAAe;AAAA,QACf,QAAQ;AAAA,QACR,aAAa;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,MACL,eAAe;AAAA,MACf,QAAQ;AAAA,MACR,aAAa;AAAA,IACf;AAAA,EACF;AAGA,QAAM,SAAS,MAAM,YAAY,MAAM,CAAC,WAAW,QAAQ,eAAe,CAAC;AAC3E,MAAI,OAAO,aAAa,KAAK,OAAO,OAAO,SAAS,GAAG;AACrD,QAAI;AACF,YAAM,WAAW,KAAK,MAAM,OAAO,MAAM;AACzC,UAAI,SAAS,SAAS,GAAG;AACvB,eAAO;AAAA,UACL,eAAe;AAAA,UACf,QAAQ;AAAA,UACR,aAAa,SAAS,CAAC,EAAE,SAAS,SAAS,CAAC,EAAE;AAAA,QAChD;AAAA,MACF;AAAA,IACF,QAAQ;AAEN,aAAO;AAAA,QACL,eAAe;AAAA,QACf,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,QAAQ;AAAA,EACV;AACF;AAKA,eAAsB,cAAgC;AACpD,QAAM,SAAS,MAAM,YAAY,SAAS,CAAC,WAAW,CAAC;AACvD,SAAO,OAAO,aAAa;AAC7B;AAKA,eAAsB,uBAAyC;AAC7D,QAAM,SAAS,MAAM,YAAY,SAAS,CAAC,SAAS,QAAQ,CAAC;AAC7D,SAAO,OAAO,aAAa;AAC7B;AAMA,eAAsB,aAAa,WAA2C;AAC5E,QAAM,SAAS,MAAM,YAAY,MAAM,CAAC,QAAQ,SAAS,CAAC;AAC1D,MAAI,OAAO,aAAa,GAAG;AACzB,WAAO;AAAA,EACT;AACA,SAAO,OAAO;AAChB;AAOA,eAAsB,gBAAgB,MAAc,OAAuC;AACzF,QAAM,SAAS,MAAM,YAAY,SAAS,CAAC,MAAM,OAAO,UAAU,OAAO,IAAI,CAAC;AAC9E,MAAI,OAAO,aAAa,GAAG;AACzB,WAAO;AAAA,EACT;AACA,SAAO,OAAO;AAChB;AAKA,eAAsB,aACpB,MACA,WACA,UACA,QACuB;AACvB,QAAM,SAAuB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb;AAEA,MAAI;AACF,YAAQ,UAAU;AAAA,MAChB,KAAK,OAAO;AACV,cAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,eAAO,YAAY,CAAC,CAAC,SAAS,MAAM,SAAS;AAC7C,YAAI,CAAC,OAAO,WAAW;AACrB,iBAAO,QAAQ;AAAA,QACjB;AACA;AAAA,MACF;AAAA,MAEA,KAAK,aAAa;AAEhB,cAAM,QAAQ,MAAM,aAAa,SAAS;AAC1C,eAAO,YAAY,UAAU;AAC7B,YAAI,CAAC,OAAO,WAAW;AACrB,iBAAO,QAAQ;AAAA,QACjB;AACA;AAAA,MACF;AAAA,MAEA,KAAK,SAAS;AAEZ,cAAM,QAAQ,UAAU,MAAM,GAAG,EAAE,IAAI,KAAK;AAC5C,cAAM,YAAY,UAAU,SAAS,GAAG,IACpC,UAAU,UAAU,GAAG,UAAU,YAAY,GAAG,CAAC,IACjD,QAAQ,SAAS;AAErB,cAAM,QAAQ,MAAM,gBAAgB,WAAW,KAAK;AACpD,eAAO,YAAY,UAAU;AAC7B,YAAI,CAAC,OAAO,WAAW;AACrB,iBAAO,QAAQ;AAAA,QACjB;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,WAAO,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,WAAO,YAAY;AAAA,EACrB;AAEA,SAAO;AACT;AAKA,eAAsB,cAAc,QAA+C;AACjF,QAAM,WAAW,OAAO,YAAY;AACpC,MAAI,gBAAgB;AAGpB,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,sBAAgB,MAAM,kBAAkB;AACxC;AAAA,IACF,KAAK;AACH,sBAAgB,MAAM,qBAAqB;AAC3C;AAAA,IACF,KAAK;AACH,sBAAgB;AAChB;AAAA,EACJ;AAEA,QAAM,UAA0B,CAAC;AAEjC,MAAI,OAAO,OAAO;AAChB,eAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,OAAO,KAAK,GAAG;AAC5D,YAAM,SAAS,MAAM,aAAa,MAAM,WAAW,UAAU,MAAM;AACnE,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,eAAe,QAAQ,WAAW,KAAK,QAAQ,MAAM,CAAC,MAAM,EAAE,SAAS;AAE7E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKA,eAAsB,YAAY,QAAwD;AACxF,QAAM,WAAW,OAAO,YAAY;AACpC,QAAM,UAAkC,CAAC;AAEzC,MAAI,CAAC,OAAO,OAAO;AACjB,WAAO;AAAA,EACT;AAEA,aAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,OAAO,KAAK,GAAG;AAC5D,QAAI;AACF,UAAI,QAAuB;AAE3B,cAAQ,UAAU;AAAA,QAChB,KAAK;AACH,kBAAQ,QAAQ,IAAI,IAAI,KAAK;AAC7B;AAAA,QAEF,KAAK;AACH,kBAAQ,MAAM,aAAa,SAAS;AACpC;AAAA,QAEF,KAAK,SAAS;AACZ,gBAAM,QAAQ,UAAU,MAAM,GAAG,EAAE,IAAI,KAAK;AAC5C,gBAAM,OAAO,UAAU,UAAU,GAAG,UAAU,YAAY,GAAG,CAAC,KAAK,OAAO,SAAS;AACnF,kBAAQ,MAAM,gBAAgB,MAAM,KAAK;AACzC;AAAA,QACF;AAAA,MACF;AAEA,UAAI,OAAO;AACT,gBAAQ,IAAI,IAAI;AAAA,MAClB;AAAA,IACF,SAAS,OAAO;AACd,aAAO,MAAM,yBAAyB,IAAI,KAAK,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,cAAc,QAA+B;AAC3D,QAAM,WAAW,OAAO,YAAY;AACpC,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,QAAQ;AAAA,IACvB;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,OAAO,SAAS,OAAO,KAAK,OAAO,KAAK,EAAE,WAAW,GAAG;AAC3D,UAAM,KAAK,uCAAuC;AAClD,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,YAAM,KAAK,iCAAiC;AAC5C,YAAM,KAAK,4DAA4D;AACvE,YAAM,KAAK,EAAE;AACb,iBAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,OAAO,KAAK,GAAG;AAC5D,cAAM,KAAK,UAAU,IAAI,eAAe,SAAS,IAAI;AAAA,MACvD;AACA;AAAA,IAEF,KAAK;AACH,YAAM,KAAK,uCAAuC;AAClD,YAAM,KAAK,mDAAmD;AAC9D,YAAM,KAAK,EAAE;AACb,UAAI,OAAO,SAAS;AAClB,cAAM,KAAK,sBAAsB,OAAO,OAAO,GAAG;AAClD,cAAM,KAAK,EAAE;AAAA,MACf;AACA,iBAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,OAAO,KAAK,GAAG;AAC5D,cAAM,OAAO,OAAO,SAAS;AAC7B,cAAM,KAAK,UAAU,IAAI,0BAA0B,SAAS,IAAI,IAAI,GAAG;AAAA,MACzE;AACA;AAAA,IAEF,KAAK;AACH,YAAM,KAAK,4DAA4D;AACvE,YAAM,KAAK,yDAAyD;AACpE,YAAM,KAAK,EAAE;AACb,YAAM,KAAK,2DAA2D;AACtE,iBAAW,QAAQ,OAAO,KAAK,OAAO,KAAK,GAAG;AAC5C,cAAM,KAAK,YAAY,IAAI,oBAAoB;AAAA,MACjD;AACA;AAAA,EACJ;AAGA,MAAI,OAAO,OAAO,iBAAiB,OAAO;AACxC,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,8CAA8C;AAAA,EAC3D;AAEA,QAAM,KAAK,EAAE;AACb,SAAO,MAAM,KAAK,IAAI;AACxB;AAKA,eAAsB,WAAW,SAAiB,QAAwC;AACxF,QAAM,YAAY,OAAO,OAAO,QAAQ;AACxC,QAAM,WAAWC,MAAK,SAAS,SAAS;AACxC,QAAM,UAAU,cAAc,MAAM;AAEpC,QAAM,UAAU,UAAU,OAAO;AACjC,SAAO;AACT;AAKA,eAAsB,SAAS,SAAiB,QAA0C;AACxF,QAAM,YAAY,QAAQ,OAAO,QAAQ;AACzC,QAAM,WAAWA,MAAK,SAAS,SAAS;AAExC,MAAI;AACF,UAAMC,QAAO,QAAQ;AACrB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,UAAU,SAAiB,QAAgD;AAC/F,QAAM,YAAY,QAAQ,OAAO,QAAQ;AACzC,QAAM,WAAWD,MAAK,SAAS,SAAS;AAExC,MAAI;AACF,UAAM,UAAU,MAAME,UAAS,UAAU,OAAO;AAChD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,gBAAgB,UAK9B;AACA,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,QACb,aAAa;AAAA,QACb,YAAY;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,QACb,aAAa;AAAA,QACb,YAAY;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,QACb,aAAa;AAAA,QACb,YAAY;AAAA,MACd;AAAA,EACJ;AACF;","names":["readFile","readFile","execa","which","readFile","join","readFile","access","join","resolve","result","join","access","readFile"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a3t/rapid-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Core library for RAPID - AI-assisted development with dev containers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Steve Rude <steve@rude.la>",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"vitest": "^3.0.5"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@a3t/rapid-schema": "0.1.
|
|
47
|
+
"@a3t/rapid-schema": "0.1.2"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsup",
|