@a3t/rapid-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,330 @@
1
+ /**
2
+ * RAPID Configuration Types
3
+ */
4
+ interface RapidConfig {
5
+ $schema?: string;
6
+ version: '1.0';
7
+ name?: string;
8
+ container?: ContainerConfig;
9
+ secrets?: SecretsConfig;
10
+ agents: AgentsConfig;
11
+ context?: ContextConfig;
12
+ mcp?: McpConfig;
13
+ }
14
+ interface ContainerConfig {
15
+ devcontainer?: string;
16
+ compose?: string;
17
+ autoStart?: boolean;
18
+ buildArgs?: Record<string, string>;
19
+ }
20
+ interface SecretsConfig {
21
+ provider?: 'env' | '1password' | 'vault';
22
+ vault?: string;
23
+ address?: string;
24
+ items?: Record<string, string>;
25
+ envrc?: EnvrcConfig;
26
+ dotenv?: DotenvConfig;
27
+ }
28
+ interface EnvrcConfig {
29
+ generate?: boolean;
30
+ path?: string;
31
+ includeLocal?: boolean;
32
+ }
33
+ interface DotenvConfig {
34
+ enabled?: boolean;
35
+ files?: string[];
36
+ warn?: boolean;
37
+ }
38
+ interface AgentsConfig {
39
+ default: string;
40
+ available: Record<string, AgentDefinition>;
41
+ }
42
+ interface AgentDefinition {
43
+ cli: string;
44
+ instructionFile?: string;
45
+ envVars?: string[];
46
+ installCmd?: string;
47
+ args?: string[];
48
+ }
49
+ interface ContextConfig {
50
+ files?: string[];
51
+ dirs?: string[];
52
+ exclude?: string[];
53
+ generateAgentFiles?: boolean;
54
+ templateDir?: string;
55
+ preserve?: string[];
56
+ }
57
+ interface McpConfig {
58
+ configFile?: string;
59
+ servers?: Record<string, McpServerConfig>;
60
+ }
61
+ interface McpServerConfig {
62
+ enabled?: boolean;
63
+ [key: string]: unknown;
64
+ }
65
+ /**
66
+ * Agent status
67
+ */
68
+ interface AgentStatus {
69
+ name: string;
70
+ available: boolean;
71
+ cliPath?: string;
72
+ version?: string;
73
+ }
74
+ /**
75
+ * Environment status
76
+ */
77
+ interface EnvironmentStatus {
78
+ configPath?: string;
79
+ configValid: boolean;
80
+ agents: AgentStatus[];
81
+ secretsLoaded: boolean;
82
+ containerRunning: boolean;
83
+ }
84
+
85
+ /**
86
+ * Configuration loading and validation
87
+ */
88
+
89
+ interface LoadedConfig {
90
+ config: RapidConfig;
91
+ filepath: string;
92
+ rootDir: string;
93
+ }
94
+ /**
95
+ * Load RAPID configuration from the current directory or ancestors
96
+ */
97
+ declare function loadConfig(cwd?: string): Promise<LoadedConfig | null>;
98
+ /**
99
+ * Load configuration from a specific file
100
+ */
101
+ declare function loadConfigFromFile(filepath: string): Promise<LoadedConfig>;
102
+ /**
103
+ * Get default configuration
104
+ */
105
+ declare function getDefaultConfig(): RapidConfig;
106
+ /**
107
+ * Merge user config with defaults
108
+ */
109
+ declare function mergeWithDefaults(config: Partial<RapidConfig>): RapidConfig;
110
+
111
+ /**
112
+ * Agent detection and management
113
+ */
114
+
115
+ /**
116
+ * Check if an agent CLI is available
117
+ */
118
+ declare function checkAgentAvailable(agent: AgentDefinition): Promise<AgentStatus>;
119
+ /**
120
+ * Check all configured agents
121
+ */
122
+ declare function checkAllAgents(config: RapidConfig): Promise<AgentStatus[]>;
123
+ /**
124
+ * Get the default agent from config
125
+ */
126
+ declare function getDefaultAgent(config: RapidConfig): AgentDefinition | null;
127
+ /**
128
+ * Get a specific agent by name
129
+ */
130
+ declare function getAgent(config: RapidConfig, name: string): AgentDefinition | null;
131
+ /**
132
+ * Launch an agent CLI
133
+ */
134
+ declare function launchAgent(agent: AgentDefinition, options?: {
135
+ cwd?: string;
136
+ env?: Record<string, string>;
137
+ stdio?: 'inherit' | 'pipe';
138
+ }): Promise<void>;
139
+
140
+ /**
141
+ * Logging utilities
142
+ */
143
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
144
+ declare function setLogLevel(level: LogLevel): void;
145
+ declare function getLogLevel(): LogLevel;
146
+ declare const logger: {
147
+ debug(message: string, ...args: unknown[]): void;
148
+ info(message: string, ...args: unknown[]): void;
149
+ success(message: string, ...args: unknown[]): void;
150
+ warn(message: string, ...args: unknown[]): void;
151
+ error(message: string, ...args: unknown[]): void;
152
+ brand(text: string): string;
153
+ dim(text: string): string;
154
+ bold(text: string): string;
155
+ header(text: string): void;
156
+ blank(): void;
157
+ };
158
+
159
+ /**
160
+ * Container management utilities
161
+ * Uses devcontainer CLI for container lifecycle
162
+ */
163
+
164
+ interface ContainerStatus {
165
+ exists: boolean;
166
+ running: boolean;
167
+ containerId?: string;
168
+ containerName?: string;
169
+ }
170
+ interface DevcontainerConfig {
171
+ name?: string;
172
+ image?: string;
173
+ dockerFile?: string;
174
+ build?: {
175
+ dockerfile?: string;
176
+ context?: string;
177
+ };
178
+ [key: string]: unknown;
179
+ }
180
+ /**
181
+ * Check if devcontainer CLI is available
182
+ */
183
+ declare function hasDevcontainerCli(): Promise<boolean>;
184
+ /**
185
+ * Check if Docker is available
186
+ */
187
+ declare function hasDocker(): Promise<boolean>;
188
+ /**
189
+ * Get the devcontainer.json path
190
+ */
191
+ declare function getDevcontainerPath(rootDir: string, config?: RapidConfig): string;
192
+ /**
193
+ * Load devcontainer.json
194
+ */
195
+ declare function loadDevcontainerConfig(rootDir: string, config?: RapidConfig): Promise<DevcontainerConfig | null>;
196
+ /**
197
+ * Get container name for a project
198
+ */
199
+ declare function getContainerName(rootDir: string, devcontainerConfig?: DevcontainerConfig): string;
200
+ /**
201
+ * Check container status using devcontainer labels
202
+ */
203
+ declare function getContainerStatus(rootDir: string, _config?: RapidConfig): Promise<ContainerStatus>;
204
+ /**
205
+ * Start the dev container using devcontainer CLI
206
+ */
207
+ declare function startContainer(rootDir: string, _config?: RapidConfig, options?: {
208
+ rebuild?: boolean;
209
+ quiet?: boolean;
210
+ }): Promise<{
211
+ success: boolean;
212
+ containerId?: string;
213
+ error?: string;
214
+ }>;
215
+ /**
216
+ * Stop the dev container
217
+ */
218
+ declare function stopContainer(rootDir: string, config?: RapidConfig, options?: {
219
+ remove?: boolean;
220
+ }): Promise<{
221
+ success: boolean;
222
+ error?: string;
223
+ }>;
224
+ /**
225
+ * Execute a command inside the dev container
226
+ */
227
+ declare function execInContainer(rootDir: string, command: string[], _config?: RapidConfig, options?: {
228
+ interactive?: boolean;
229
+ tty?: boolean;
230
+ env?: Record<string, string>;
231
+ }): Promise<void>;
232
+
233
+ /**
234
+ * Secrets management for RAPID
235
+ * Supports 1Password, HashiCorp Vault, and environment variables
236
+ */
237
+
238
+ interface SecretStatus {
239
+ name: string;
240
+ reference: string;
241
+ provider: 'env' | '1password' | 'vault';
242
+ available: boolean;
243
+ error?: string;
244
+ }
245
+ interface SecretsStatus {
246
+ provider: 'env' | '1password' | 'vault';
247
+ authenticated: boolean;
248
+ authMethod?: 'service-account' | 'user' | 'token';
249
+ secrets: SecretStatus[];
250
+ allAvailable: boolean;
251
+ }
252
+ interface OpAuthStatus {
253
+ authenticated: boolean;
254
+ method: 'service-account' | 'user' | 'none';
255
+ accountInfo?: string;
256
+ }
257
+ /**
258
+ * Check if 1Password CLI is installed
259
+ */
260
+ declare function hasOpCli(): Promise<boolean>;
261
+ /**
262
+ * Check if OP_SERVICE_ACCOUNT_TOKEN is set
263
+ */
264
+ declare function hasOpServiceAccountToken(): boolean;
265
+ /**
266
+ * Check if 1Password CLI is authenticated (via service account or user)
267
+ */
268
+ declare function isOpAuthenticated(): Promise<boolean>;
269
+ /**
270
+ * Get detailed 1Password authentication status
271
+ */
272
+ declare function getOpAuthStatus(): Promise<OpAuthStatus>;
273
+ /**
274
+ * Check if HashiCorp Vault CLI is installed
275
+ */
276
+ declare function hasVaultCli(): Promise<boolean>;
277
+ /**
278
+ * Check if HashiCorp Vault is authenticated
279
+ */
280
+ declare function isVaultAuthenticated(): Promise<boolean>;
281
+ /**
282
+ * Read a secret from 1Password
283
+ * @param reference - 1Password reference (e.g., "op://vault/item/field")
284
+ */
285
+ declare function readOpSecret(reference: string): Promise<string | null>;
286
+ /**
287
+ * Read a secret from HashiCorp Vault
288
+ * @param path - Vault path (e.g., "secret/data/myproject")
289
+ * @param field - Field name within the secret
290
+ */
291
+ declare function readVaultSecret(path: string, field: string): Promise<string | null>;
292
+ /**
293
+ * Verify a single secret is accessible
294
+ */
295
+ declare function verifySecret(name: string, reference: string, provider: 'env' | '1password' | 'vault', config?: SecretsConfig): Promise<SecretStatus>;
296
+ /**
297
+ * Verify all secrets in configuration
298
+ */
299
+ declare function verifySecrets(config: SecretsConfig): Promise<SecretsStatus>;
300
+ /**
301
+ * Load all secrets into environment
302
+ */
303
+ declare function loadSecrets(config: SecretsConfig): Promise<Record<string, string>>;
304
+ /**
305
+ * Generate .envrc file from secrets configuration
306
+ */
307
+ declare function generateEnvrc(config: SecretsConfig): string;
308
+ /**
309
+ * Write .envrc file to project directory
310
+ */
311
+ declare function writeEnvrc(rootDir: string, config: SecretsConfig): Promise<string>;
312
+ /**
313
+ * Check if .envrc exists in project
314
+ */
315
+ declare function hasEnvrc(rootDir: string, config?: SecretsConfig): Promise<boolean>;
316
+ /**
317
+ * Read existing .envrc content
318
+ */
319
+ declare function readEnvrc(rootDir: string, config?: SecretsConfig): Promise<string | null>;
320
+ /**
321
+ * Get a summary of provider requirements
322
+ */
323
+ declare function getProviderInfo(provider: 'env' | '1password' | 'vault'): {
324
+ name: string;
325
+ cliRequired: string | null;
326
+ authCommand: string | null;
327
+ installUrl: string | null;
328
+ };
329
+
330
+ export { type AgentDefinition, type AgentStatus, type AgentsConfig, type ContainerConfig, type ContainerStatus, type ContextConfig, type DevcontainerConfig, type DotenvConfig, type EnvironmentStatus, type EnvrcConfig, type LoadedConfig, type LogLevel, type McpConfig, type McpServerConfig, type OpAuthStatus, type RapidConfig, type SecretStatus, type SecretsConfig, type SecretsStatus, checkAgentAvailable, checkAllAgents, execInContainer, generateEnvrc, getAgent, getContainerName, getContainerStatus, 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 ADDED
@@ -0,0 +1,721 @@
1
+ // src/config.ts
2
+ import { cosmiconfig } from "cosmiconfig";
3
+ import { readFile } from "fs/promises";
4
+ import { dirname, resolve } from "path";
5
+ var CONFIG_NAME = "rapid";
6
+ var CONFIG_FILES = ["rapid.json", "rapid.config.json", ".rapidrc", ".rapidrc.json"];
7
+ async function loadConfig(cwd) {
8
+ const explorer = cosmiconfig(CONFIG_NAME, {
9
+ searchPlaces: CONFIG_FILES,
10
+ loaders: {
11
+ ".json": async (filepath) => {
12
+ const content = await readFile(filepath, "utf-8");
13
+ return JSON.parse(content);
14
+ }
15
+ }
16
+ });
17
+ const result = await explorer.search(cwd);
18
+ if (!result || result.isEmpty) {
19
+ return null;
20
+ }
21
+ return {
22
+ config: result.config,
23
+ filepath: result.filepath,
24
+ rootDir: dirname(result.filepath)
25
+ };
26
+ }
27
+ async function loadConfigFromFile(filepath) {
28
+ const content = await readFile(filepath, "utf-8");
29
+ const config = JSON.parse(content);
30
+ return {
31
+ config,
32
+ filepath: resolve(filepath),
33
+ rootDir: dirname(resolve(filepath))
34
+ };
35
+ }
36
+ function getDefaultConfig() {
37
+ return {
38
+ version: "1.0",
39
+ agents: {
40
+ default: "claude",
41
+ available: {
42
+ claude: {
43
+ cli: "claude",
44
+ instructionFile: "CLAUDE.md",
45
+ envVars: ["ANTHROPIC_API_KEY"]
46
+ },
47
+ opencode: {
48
+ cli: "opencode",
49
+ instructionFile: "AGENTS.md",
50
+ envVars: ["ANTHROPIC_API_KEY"]
51
+ },
52
+ aider: {
53
+ cli: "aider",
54
+ instructionFile: "AGENTS.md",
55
+ envVars: ["ANTHROPIC_API_KEY"],
56
+ args: ["--model", "claude-3-5-sonnet-20241022"]
57
+ }
58
+ }
59
+ },
60
+ secrets: {
61
+ provider: "env"
62
+ },
63
+ context: {
64
+ files: ["README.md"],
65
+ dirs: ["docs/"],
66
+ generateAgentFiles: true
67
+ }
68
+ };
69
+ }
70
+ function mergeWithDefaults(config) {
71
+ const defaults = getDefaultConfig();
72
+ return {
73
+ ...defaults,
74
+ ...config,
75
+ agents: {
76
+ ...defaults.agents,
77
+ ...config.agents,
78
+ available: {
79
+ ...defaults.agents.available,
80
+ ...config.agents?.available
81
+ }
82
+ },
83
+ secrets: {
84
+ ...defaults.secrets,
85
+ ...config.secrets
86
+ },
87
+ context: {
88
+ ...defaults.context,
89
+ ...config.context
90
+ }
91
+ };
92
+ }
93
+
94
+ // src/agents.ts
95
+ import { execa } from "execa";
96
+ import which from "which";
97
+ async function checkAgentAvailable(agent) {
98
+ try {
99
+ const cliPath = await which(agent.cli);
100
+ let version;
101
+ try {
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
+ }
149
+
150
+ // src/logger.ts
151
+ import chalk from "chalk";
152
+ var LOG_LEVELS = {
153
+ debug: 0,
154
+ info: 1,
155
+ warn: 2,
156
+ error: 3
157
+ };
158
+ var currentLevel = "info";
159
+ function setLogLevel(level) {
160
+ currentLevel = level;
161
+ }
162
+ function getLogLevel() {
163
+ return currentLevel;
164
+ }
165
+ function shouldLog(level) {
166
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
167
+ }
168
+ var logger = {
169
+ debug(message, ...args) {
170
+ if (shouldLog("debug")) {
171
+ console.log(chalk.gray(`[debug] ${message}`), ...args);
172
+ }
173
+ },
174
+ info(message, ...args) {
175
+ if (shouldLog("info")) {
176
+ console.log(chalk.blue("\u2139"), message, ...args);
177
+ }
178
+ },
179
+ success(message, ...args) {
180
+ if (shouldLog("info")) {
181
+ console.log(chalk.green("\u2713"), message, ...args);
182
+ }
183
+ },
184
+ warn(message, ...args) {
185
+ if (shouldLog("warn")) {
186
+ console.log(chalk.yellow("\u26A0"), message, ...args);
187
+ }
188
+ },
189
+ error(message, ...args) {
190
+ if (shouldLog("error")) {
191
+ console.error(chalk.red("\u2717"), message, ...args);
192
+ }
193
+ },
194
+ // Styled output helpers
195
+ brand(text) {
196
+ return chalk.hex("#818cf8")(text);
197
+ },
198
+ dim(text) {
199
+ return chalk.dim(text);
200
+ },
201
+ bold(text) {
202
+ return chalk.bold(text);
203
+ },
204
+ // Print a header
205
+ header(text) {
206
+ console.log();
207
+ console.log(chalk.bold(text));
208
+ console.log(chalk.dim("\u2500".repeat(text.length)));
209
+ },
210
+ // Print a blank line
211
+ blank() {
212
+ console.log();
213
+ }
214
+ };
215
+
216
+ // src/container.ts
217
+ import { execa as execa2 } from "execa";
218
+ import which2 from "which";
219
+ import { readFile as readFile2 } from "fs/promises";
220
+ import { join } from "path";
221
+ async function hasDevcontainerCli() {
222
+ try {
223
+ await which2("devcontainer");
224
+ return true;
225
+ } catch {
226
+ return false;
227
+ }
228
+ }
229
+ async function hasDocker() {
230
+ try {
231
+ await execa2("docker", ["info"], { timeout: 5e3 });
232
+ return true;
233
+ } catch {
234
+ return false;
235
+ }
236
+ }
237
+ function getDevcontainerPath(rootDir, config) {
238
+ const customPath = config?.container?.devcontainer;
239
+ if (customPath) {
240
+ return join(rootDir, customPath);
241
+ }
242
+ return join(rootDir, ".devcontainer", "devcontainer.json");
243
+ }
244
+ async function loadDevcontainerConfig(rootDir, config) {
245
+ try {
246
+ const configPath = getDevcontainerPath(rootDir, config);
247
+ const content = await readFile2(configPath, "utf-8");
248
+ return JSON.parse(content);
249
+ } catch {
250
+ return null;
251
+ }
252
+ }
253
+ function getContainerName(rootDir, devcontainerConfig) {
254
+ const dirName = rootDir.split("/").pop() || "rapid";
255
+ const name = devcontainerConfig?.name || dirName;
256
+ return `rapid-${name}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
257
+ }
258
+ async function getContainerStatus(rootDir, _config) {
259
+ try {
260
+ const result = await execa2("docker", [
261
+ "ps",
262
+ "-a",
263
+ "--filter",
264
+ `label=devcontainer.local_folder=${rootDir}`,
265
+ "--format",
266
+ "{{.ID}} {{.State}} {{.Names}}"
267
+ ]);
268
+ const lines = result.stdout.trim().split("\n").filter(Boolean);
269
+ if (lines.length === 0) {
270
+ return { exists: false, running: false };
271
+ }
272
+ const parts = lines[0]?.split(" ");
273
+ const containerId = parts?.[0];
274
+ const state = parts?.[1];
275
+ const containerName = parts?.[2];
276
+ if (!containerId || !containerName) {
277
+ return { exists: false, running: false };
278
+ }
279
+ return {
280
+ exists: true,
281
+ running: state === "running",
282
+ containerId,
283
+ containerName
284
+ };
285
+ } catch {
286
+ return { exists: false, running: false };
287
+ }
288
+ }
289
+ async function startContainer(rootDir, _config, options = {}) {
290
+ const hasDevCli = await hasDevcontainerCli();
291
+ if (!hasDevCli) {
292
+ return {
293
+ success: false,
294
+ error: "devcontainer CLI not found. Install with: npm install -g @devcontainers/cli"
295
+ };
296
+ }
297
+ const hasDockerRunning = await hasDocker();
298
+ if (!hasDockerRunning) {
299
+ return {
300
+ success: false,
301
+ error: "Docker is not running. Please start Docker Desktop."
302
+ };
303
+ }
304
+ try {
305
+ const args = ["up", "--workspace-folder", rootDir];
306
+ if (options.rebuild) {
307
+ args.push("--remove-existing-container");
308
+ }
309
+ const result = await execa2("devcontainer", args, {
310
+ stdio: options.quiet ? "pipe" : "inherit",
311
+ cwd: rootDir
312
+ });
313
+ if (options.quiet && result.stdout) {
314
+ try {
315
+ const output = JSON.parse(result.stdout);
316
+ return { success: true, containerId: output.containerId };
317
+ } catch {
318
+ return { success: true };
319
+ }
320
+ }
321
+ return { success: true };
322
+ } catch (error) {
323
+ const execError = error;
324
+ const stderr = typeof execError.stderr === "string" ? execError.stderr : void 0;
325
+ return {
326
+ success: false,
327
+ error: stderr || execError.message
328
+ };
329
+ }
330
+ }
331
+ async function stopContainer(rootDir, config, options = {}) {
332
+ const status = await getContainerStatus(rootDir, config);
333
+ if (!status.exists) {
334
+ return { success: true };
335
+ }
336
+ try {
337
+ if (status.running) {
338
+ await execa2("docker", ["stop", status.containerId]);
339
+ }
340
+ if (options.remove) {
341
+ await execa2("docker", ["rm", status.containerId]);
342
+ }
343
+ return { success: true };
344
+ } catch (error) {
345
+ const execError = error;
346
+ const stderr = typeof execError.stderr === "string" ? execError.stderr : void 0;
347
+ return {
348
+ success: false,
349
+ error: stderr || execError.message
350
+ };
351
+ }
352
+ }
353
+ async function execInContainer(rootDir, command, _config, options = {}) {
354
+ const hasDevCli = await hasDevcontainerCli();
355
+ if (!hasDevCli) {
356
+ throw new Error("devcontainer CLI not found. Install with: npm install -g @devcontainers/cli");
357
+ }
358
+ const args = ["exec", "--workspace-folder", rootDir];
359
+ if (options.env) {
360
+ for (const [key, value] of Object.entries(options.env)) {
361
+ args.push("--remote-env", `${key}=${value}`);
362
+ }
363
+ }
364
+ args.push(...command);
365
+ await execa2("devcontainer", args, {
366
+ stdio: "inherit",
367
+ cwd: rootDir
368
+ });
369
+ }
370
+
371
+ // src/secrets.ts
372
+ import { spawn } from "child_process";
373
+ import { readFile as readFile3, writeFile, access } from "fs/promises";
374
+ import { join as join2 } from "path";
375
+ async function execCommand(command, args, options = {}) {
376
+ return new Promise((resolve2) => {
377
+ const proc = spawn(command, args, {
378
+ stdio: ["pipe", "pipe", "pipe"],
379
+ timeout: options.timeout ?? 3e4
380
+ });
381
+ let stdout = "";
382
+ let stderr = "";
383
+ proc.stdout?.on("data", (data) => {
384
+ stdout += data.toString();
385
+ });
386
+ proc.stderr?.on("data", (data) => {
387
+ stderr += data.toString();
388
+ });
389
+ proc.on("close", (code) => {
390
+ resolve2({ stdout: stdout.trim(), stderr: stderr.trim(), exitCode: code ?? 1 });
391
+ });
392
+ proc.on("error", (err) => {
393
+ resolve2({ stdout: "", stderr: err.message, exitCode: 1 });
394
+ });
395
+ });
396
+ }
397
+ async function hasOpCli() {
398
+ const result = await execCommand("op", ["--version"]);
399
+ return result.exitCode === 0;
400
+ }
401
+ function hasOpServiceAccountToken() {
402
+ return !!process.env.OP_SERVICE_ACCOUNT_TOKEN;
403
+ }
404
+ async function isOpAuthenticated() {
405
+ if (hasOpServiceAccountToken()) {
406
+ const result2 = await execCommand("op", ["vault", "list", "--format=json"]);
407
+ return result2.exitCode === 0;
408
+ }
409
+ const result = await execCommand("op", ["account", "list"]);
410
+ return result.exitCode === 0 && result.stdout.length > 0;
411
+ }
412
+ async function getOpAuthStatus() {
413
+ if (hasOpServiceAccountToken()) {
414
+ const result2 = await execCommand("op", ["vault", "list", "--format=json"]);
415
+ if (result2.exitCode === 0) {
416
+ return {
417
+ authenticated: true,
418
+ method: "service-account",
419
+ accountInfo: "Service Account"
420
+ };
421
+ }
422
+ return {
423
+ authenticated: false,
424
+ method: "none",
425
+ accountInfo: "Invalid service account token"
426
+ };
427
+ }
428
+ const result = await execCommand("op", ["account", "list", "--format=json"]);
429
+ if (result.exitCode === 0 && result.stdout.length > 0) {
430
+ try {
431
+ const accounts = JSON.parse(result.stdout);
432
+ if (accounts.length > 0) {
433
+ return {
434
+ authenticated: true,
435
+ method: "user",
436
+ accountInfo: accounts[0].email || accounts[0].url
437
+ };
438
+ }
439
+ } catch {
440
+ return {
441
+ authenticated: true,
442
+ method: "user"
443
+ };
444
+ }
445
+ }
446
+ return {
447
+ authenticated: false,
448
+ method: "none"
449
+ };
450
+ }
451
+ async function hasVaultCli() {
452
+ const result = await execCommand("vault", ["--version"]);
453
+ return result.exitCode === 0;
454
+ }
455
+ async function isVaultAuthenticated() {
456
+ const result = await execCommand("vault", ["token", "lookup"]);
457
+ return result.exitCode === 0;
458
+ }
459
+ async function readOpSecret(reference) {
460
+ const result = await execCommand("op", ["read", reference]);
461
+ if (result.exitCode !== 0) {
462
+ return null;
463
+ }
464
+ return result.stdout;
465
+ }
466
+ async function readVaultSecret(path, field) {
467
+ const result = await execCommand("vault", ["kv", "get", "-field", field, path]);
468
+ if (result.exitCode !== 0) {
469
+ return null;
470
+ }
471
+ return result.stdout;
472
+ }
473
+ async function verifySecret(name, reference, provider, config) {
474
+ const status = {
475
+ name,
476
+ reference,
477
+ provider,
478
+ available: false
479
+ };
480
+ try {
481
+ switch (provider) {
482
+ case "env": {
483
+ const value = process.env[name];
484
+ status.available = !!value && value.length > 0;
485
+ if (!status.available) {
486
+ status.error = "Environment variable not set";
487
+ }
488
+ break;
489
+ }
490
+ case "1password": {
491
+ const value = await readOpSecret(reference);
492
+ status.available = value !== null;
493
+ if (!status.available) {
494
+ status.error = "Secret not found in 1Password";
495
+ }
496
+ break;
497
+ }
498
+ case "vault": {
499
+ const field = reference.split("/").pop() || "value";
500
+ const vaultPath = reference.includes("/") ? reference.substring(0, reference.lastIndexOf("/")) : config?.vault || "secret/data/default";
501
+ const value = await readVaultSecret(vaultPath, field);
502
+ status.available = value !== null;
503
+ if (!status.available) {
504
+ status.error = "Secret not found in Vault";
505
+ }
506
+ break;
507
+ }
508
+ }
509
+ } catch (error) {
510
+ status.error = error instanceof Error ? error.message : String(error);
511
+ status.available = false;
512
+ }
513
+ return status;
514
+ }
515
+ async function verifySecrets(config) {
516
+ const provider = config.provider || "env";
517
+ let authenticated = true;
518
+ switch (provider) {
519
+ case "1password":
520
+ authenticated = await isOpAuthenticated();
521
+ break;
522
+ case "vault":
523
+ authenticated = await isVaultAuthenticated();
524
+ break;
525
+ case "env":
526
+ authenticated = true;
527
+ break;
528
+ }
529
+ const secrets = [];
530
+ if (config.items) {
531
+ for (const [name, reference] of Object.entries(config.items)) {
532
+ const status = await verifySecret(name, reference, provider, config);
533
+ secrets.push(status);
534
+ }
535
+ }
536
+ const allAvailable = secrets.length === 0 || secrets.every((s) => s.available);
537
+ return {
538
+ provider,
539
+ authenticated,
540
+ secrets,
541
+ allAvailable
542
+ };
543
+ }
544
+ async function loadSecrets(config) {
545
+ const provider = config.provider || "env";
546
+ const secrets = {};
547
+ if (!config.items) {
548
+ return secrets;
549
+ }
550
+ for (const [name, reference] of Object.entries(config.items)) {
551
+ try {
552
+ let value = null;
553
+ switch (provider) {
554
+ case "env":
555
+ value = process.env[name] || null;
556
+ break;
557
+ case "1password":
558
+ value = await readOpSecret(reference);
559
+ break;
560
+ case "vault": {
561
+ const field = reference.split("/").pop() || "value";
562
+ const path = reference.substring(0, reference.lastIndexOf("/")) || config.vault || "";
563
+ value = await readVaultSecret(path, field);
564
+ break;
565
+ }
566
+ }
567
+ if (value) {
568
+ secrets[name] = value;
569
+ }
570
+ } catch (error) {
571
+ logger.debug(`Failed to load secret ${name}: ${error}`);
572
+ }
573
+ }
574
+ return secrets;
575
+ }
576
+ function generateEnvrc(config) {
577
+ const provider = config.provider || "env";
578
+ const lines = [
579
+ "# .envrc - RAPID project secrets",
580
+ "# This file is safe to commit - it contains NO secrets, only references",
581
+ "#",
582
+ `# Provider: ${provider}`,
583
+ `# Generated by: rapid secrets generate`,
584
+ ""
585
+ ];
586
+ if (!config.items || Object.keys(config.items).length === 0) {
587
+ lines.push("# No secrets configured in rapid.json");
588
+ return lines.join("\n");
589
+ }
590
+ switch (provider) {
591
+ case "1password":
592
+ lines.push("# Secrets loaded from 1Password");
593
+ lines.push("# Requires: 1Password CLI (op) installed and authenticated");
594
+ lines.push("");
595
+ for (const [name, reference] of Object.entries(config.items)) {
596
+ lines.push(`export ${name}=$(op read "${reference}")`);
597
+ }
598
+ break;
599
+ case "vault":
600
+ lines.push("# Secrets loaded from HashiCorp Vault");
601
+ lines.push("# Requires: Vault CLI installed and authenticated");
602
+ lines.push("");
603
+ if (config.address) {
604
+ lines.push(`export VAULT_ADDR="${config.address}"`);
605
+ lines.push("");
606
+ }
607
+ for (const [name, reference] of Object.entries(config.items)) {
608
+ const path = config.vault || "secret/data/default";
609
+ lines.push(`export ${name}=$(vault kv get -field=${reference} ${path})`);
610
+ }
611
+ break;
612
+ case "env":
613
+ lines.push("# WARNING: env provider expects secrets to be set manually");
614
+ lines.push("# Consider using 1password or vault for better security");
615
+ lines.push("");
616
+ lines.push("# Uncomment and set values (DO NOT commit actual values!)");
617
+ for (const name of Object.keys(config.items)) {
618
+ lines.push(`# export ${name}="your-value-here"`);
619
+ }
620
+ break;
621
+ }
622
+ if (config.envrc?.includeLocal !== false) {
623
+ lines.push("");
624
+ lines.push("# Load local overrides if present");
625
+ lines.push("[[ -f .env.local ]] && source_env .env.local");
626
+ }
627
+ lines.push("");
628
+ return lines.join("\n");
629
+ }
630
+ async function writeEnvrc(rootDir, config) {
631
+ const envrcPath = config.envrc?.path || ".envrc";
632
+ const fullPath = join2(rootDir, envrcPath);
633
+ const content = generateEnvrc(config);
634
+ await writeFile(fullPath, content);
635
+ return fullPath;
636
+ }
637
+ async function hasEnvrc(rootDir, config) {
638
+ const envrcPath = config?.envrc?.path || ".envrc";
639
+ const fullPath = join2(rootDir, envrcPath);
640
+ try {
641
+ await access(fullPath);
642
+ return true;
643
+ } catch {
644
+ return false;
645
+ }
646
+ }
647
+ async function readEnvrc(rootDir, config) {
648
+ const envrcPath = config?.envrc?.path || ".envrc";
649
+ const fullPath = join2(rootDir, envrcPath);
650
+ try {
651
+ const content = await readFile3(fullPath, "utf-8");
652
+ return content;
653
+ } catch {
654
+ return null;
655
+ }
656
+ }
657
+ function getProviderInfo(provider) {
658
+ switch (provider) {
659
+ case "1password":
660
+ return {
661
+ name: "1Password",
662
+ cliRequired: "op",
663
+ authCommand: "eval $(op signin)",
664
+ installUrl: "https://developer.1password.com/docs/cli/get-started/"
665
+ };
666
+ case "vault":
667
+ return {
668
+ name: "HashiCorp Vault",
669
+ cliRequired: "vault",
670
+ authCommand: "vault login",
671
+ installUrl: "https://developer.hashicorp.com/vault/docs/install"
672
+ };
673
+ case "env":
674
+ return {
675
+ name: "Environment Variables",
676
+ cliRequired: null,
677
+ authCommand: null,
678
+ installUrl: null
679
+ };
680
+ }
681
+ }
682
+ export {
683
+ checkAgentAvailable,
684
+ checkAllAgents,
685
+ execInContainer,
686
+ generateEnvrc,
687
+ getAgent,
688
+ getContainerName,
689
+ getContainerStatus,
690
+ getDefaultAgent,
691
+ getDefaultConfig,
692
+ getDevcontainerPath,
693
+ getLogLevel,
694
+ getOpAuthStatus,
695
+ getProviderInfo,
696
+ hasDevcontainerCli,
697
+ hasDocker,
698
+ hasEnvrc,
699
+ hasOpCli,
700
+ hasOpServiceAccountToken,
701
+ hasVaultCli,
702
+ isOpAuthenticated,
703
+ isVaultAuthenticated,
704
+ launchAgent,
705
+ loadConfig,
706
+ loadConfigFromFile,
707
+ loadDevcontainerConfig,
708
+ loadSecrets,
709
+ logger,
710
+ mergeWithDefaults,
711
+ readEnvrc,
712
+ readOpSecret,
713
+ readVaultSecret,
714
+ setLogLevel,
715
+ startContainer,
716
+ stopContainer,
717
+ verifySecret,
718
+ verifySecrets,
719
+ writeEnvrc
720
+ };
721
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@a3t/rapid-core",
3
+ "version": "0.1.0",
4
+ "description": "Core library for RAPID - AI-assisted development with dev containers",
5
+ "license": "MIT",
6
+ "author": "Steve Rude <steve@rude.la>",
7
+ "homepage": "https://getrapid.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/a3tai/rapid.git",
11
+ "directory": "packages/core"
12
+ },
13
+ "keywords": [
14
+ "rapid",
15
+ "ai",
16
+ "devcontainer",
17
+ "claude",
18
+ "opencode",
19
+ "development"
20
+ ],
21
+ "type": "module",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "main": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "files": [
31
+ "dist"
32
+ ],
33
+ "dependencies": {
34
+ "chalk": "^5.4.1",
35
+ "cosmiconfig": "^9.0.0",
36
+ "execa": "^9.6.1",
37
+ "which": "^5.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^22.13.0",
41
+ "@types/which": "^3.0.4",
42
+ "tsup": "^8.5.1",
43
+ "typescript": "^5.9.3",
44
+ "vitest": "^3.0.5"
45
+ },
46
+ "peerDependencies": {
47
+ "@a3t/rapid-schema": "0.1.0"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "typecheck": "tsc --noEmit",
53
+ "test": "echo 'No tests yet'",
54
+ "clean": "rm -rf dist .turbo"
55
+ }
56
+ }