@a3t/rapid 0.1.12 → 0.1.14
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/dist/bin.js +1 -1
- package/dist/{chunk-52NWSTTE.js → chunk-COGUXZI3.js} +965 -511
- package/dist/chunk-COGUXZI3.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-52NWSTTE.js.map +0 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { Command as
|
|
3
|
-
import { setLogLevel, logger as
|
|
2
|
+
import { Command as Command14 } from "commander";
|
|
3
|
+
import { setLogLevel, logger as logger16 } from "@a3t/rapid-core";
|
|
4
4
|
import { readFileSync as readFileSync2 } from "fs";
|
|
5
5
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6
|
-
import { dirname as dirname4, join as
|
|
6
|
+
import { dirname as dirname4, join as join8 } from "path";
|
|
7
7
|
|
|
8
8
|
// src/commands/init.ts
|
|
9
9
|
import { Command } from "commander";
|
|
10
|
-
import { writeFile, access, readFile, readdir, mkdir } from "fs/promises";
|
|
11
|
-
import { join } from "path";
|
|
10
|
+
import { writeFile as writeFile2, access, readFile, readdir, mkdir as mkdir2 } from "fs/promises";
|
|
11
|
+
import { join as join2 } from "path";
|
|
12
12
|
import { existsSync } from "fs";
|
|
13
13
|
import {
|
|
14
14
|
getDefaultConfig,
|
|
15
|
-
logger,
|
|
15
|
+
logger as logger2,
|
|
16
16
|
MCP_SERVER_TEMPLATES,
|
|
17
17
|
addMcpServerFromTemplate,
|
|
18
18
|
getSecretReferences,
|
|
@@ -20,9 +20,203 @@ import {
|
|
|
20
20
|
writeOpenCodeConfig,
|
|
21
21
|
RAPID_METHODOLOGY,
|
|
22
22
|
MCP_USAGE_GUIDELINES,
|
|
23
|
-
GIT_GUIDELINES
|
|
23
|
+
GIT_GUIDELINES,
|
|
24
|
+
formatJson as formatJson2
|
|
24
25
|
} from "@a3t/rapid-core";
|
|
25
26
|
import ora from "ora";
|
|
27
|
+
|
|
28
|
+
// src/templates/claude-plugin.ts
|
|
29
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
30
|
+
import { join } from "path";
|
|
31
|
+
import { formatJson, logger } from "@a3t/rapid-core";
|
|
32
|
+
function getPluginManifest(projectName) {
|
|
33
|
+
return {
|
|
34
|
+
name: `${projectName}-rapid`,
|
|
35
|
+
version: "1.0.0",
|
|
36
|
+
description: `RAPID plugin for ${projectName}`,
|
|
37
|
+
commands: [
|
|
38
|
+
"commands/rapid-status.md",
|
|
39
|
+
"commands/rapid-worktree.md",
|
|
40
|
+
"commands/rapid-context.md",
|
|
41
|
+
"commands/rapid-mcp.md"
|
|
42
|
+
],
|
|
43
|
+
skills: ["skills/rapid-methodology.md", "skills/mcp-usage.md"]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
var COMMAND_RAPID_STATUS = `---
|
|
47
|
+
description: Check RAPID environment status
|
|
48
|
+
allowed-tools: Bash(rapid:*)
|
|
49
|
+
argument-hint: [--json]
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
Check the current RAPID environment status.
|
|
53
|
+
|
|
54
|
+
Run: \`rapid status $ARGUMENTS\`
|
|
55
|
+
|
|
56
|
+
This command shows:
|
|
57
|
+
- Container status (running/stopped)
|
|
58
|
+
- Configured agents
|
|
59
|
+
- MCP server status
|
|
60
|
+
- Secrets status
|
|
61
|
+
`;
|
|
62
|
+
var COMMAND_RAPID_WORKTREE = `---
|
|
63
|
+
description: Manage git worktrees for branch isolation
|
|
64
|
+
allowed-tools: Bash(rapid:*, git:*)
|
|
65
|
+
argument-hint: <create|list|remove> [branch]
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
Manage git worktrees for isolated feature branch development.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
- \`/rapid-worktree list\` - List all worktrees
|
|
73
|
+
- \`/rapid-worktree create <branch>\` - Create a worktree for a branch
|
|
74
|
+
- \`/rapid-worktree remove <path>\` - Remove a worktree
|
|
75
|
+
|
|
76
|
+
Run: \`rapid worktree $ARGUMENTS\`
|
|
77
|
+
`;
|
|
78
|
+
var COMMAND_RAPID_CONTEXT = `---
|
|
79
|
+
description: Show or inject project context
|
|
80
|
+
allowed-tools: Bash(rapid:*)
|
|
81
|
+
argument-hint: [show|inject]
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
Show or inject project context from rapid.json configuration.
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
- \`/rapid-context show\` - Display current context configuration
|
|
89
|
+
- \`/rapid-context inject\` - Output assembled context (for hooks)
|
|
90
|
+
|
|
91
|
+
Run: \`rapid context $ARGUMENTS\`
|
|
92
|
+
`;
|
|
93
|
+
var COMMAND_RAPID_MCP = `---
|
|
94
|
+
description: Manage MCP servers
|
|
95
|
+
allowed-tools: Bash(rapid:*)
|
|
96
|
+
argument-hint: <add|remove|list> [server]
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
Manage Model Context Protocol (MCP) servers.
|
|
100
|
+
|
|
101
|
+
## Usage
|
|
102
|
+
|
|
103
|
+
- \`/rapid-mcp list\` - List configured MCP servers
|
|
104
|
+
- \`/rapid-mcp add <server>\` - Add an MCP server from templates
|
|
105
|
+
- \`/rapid-mcp remove <server>\` - Remove an MCP server
|
|
106
|
+
|
|
107
|
+
Run: \`rapid mcp $ARGUMENTS\`
|
|
108
|
+
`;
|
|
109
|
+
var SKILL_RAPID_METHODOLOGY = `---
|
|
110
|
+
description: Apply the RAPID 5-phase development methodology
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# RAPID Methodology
|
|
114
|
+
|
|
115
|
+
When working on this project, follow the RAPID 5-phase approach:
|
|
116
|
+
|
|
117
|
+
## 1. Research Phase
|
|
118
|
+
- Understand the codebase structure and existing patterns
|
|
119
|
+
- Use grep, find, and read tools to explore before making changes
|
|
120
|
+
- Identify dependencies and potential impacts
|
|
121
|
+
|
|
122
|
+
## 2. Augment Phase
|
|
123
|
+
- Gather additional context from documentation and MCP servers
|
|
124
|
+
- Use Context7 for library documentation
|
|
125
|
+
- Use Tavily for web searches when needed
|
|
126
|
+
|
|
127
|
+
## 3. Plan Phase
|
|
128
|
+
- Break down the task into concrete steps
|
|
129
|
+
- Identify files that need to be created or modified
|
|
130
|
+
- Consider edge cases and error handling
|
|
131
|
+
|
|
132
|
+
## 4. Integrate Phase
|
|
133
|
+
- Make changes incrementally, testing each step
|
|
134
|
+
- Follow existing code patterns and conventions
|
|
135
|
+
- Run tests after each significant change
|
|
136
|
+
|
|
137
|
+
## 5. Develop Phase
|
|
138
|
+
- Complete the implementation
|
|
139
|
+
- Write or update tests as needed
|
|
140
|
+
- Document changes in code comments where helpful
|
|
141
|
+
`;
|
|
142
|
+
var SKILL_MCP_USAGE = `---
|
|
143
|
+
description: Guidelines for using MCP servers effectively
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
# MCP Server Usage Guidelines
|
|
147
|
+
|
|
148
|
+
## Available Servers
|
|
149
|
+
|
|
150
|
+
Check configured MCP servers with: \`rapid mcp list\`
|
|
151
|
+
|
|
152
|
+
## Common Servers
|
|
153
|
+
|
|
154
|
+
### Context7
|
|
155
|
+
Use for up-to-date library documentation:
|
|
156
|
+
1. First resolve library ID: \`mcp__context7__resolve-library-id\`
|
|
157
|
+
2. Then query docs: \`mcp__context7__query-docs\`
|
|
158
|
+
|
|
159
|
+
### Tavily
|
|
160
|
+
Use for web searches and content extraction:
|
|
161
|
+
- \`mcp__tavily__tavily_search\` - Search the web
|
|
162
|
+
- \`mcp__tavily__tavily_extract\` - Extract content from URLs
|
|
163
|
+
|
|
164
|
+
## Best Practices
|
|
165
|
+
|
|
166
|
+
1. Always check if an MCP server is available before using it
|
|
167
|
+
2. Prefer MCP servers over manual web searches
|
|
168
|
+
3. Cache relevant documentation locally when possible
|
|
169
|
+
4. Use specific queries for better results
|
|
170
|
+
`;
|
|
171
|
+
function getHooksConfig() {
|
|
172
|
+
return {
|
|
173
|
+
// SessionStart hook is not currently supported via JSON config
|
|
174
|
+
// This is a placeholder for future hook support
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
async function createClaudePlugin(rootDir, projectName, _options = {}) {
|
|
178
|
+
const pluginDir = join(rootDir, ".claude-plugin");
|
|
179
|
+
const commandsDir = join(pluginDir, "commands");
|
|
180
|
+
const skillsDir = join(pluginDir, "skills");
|
|
181
|
+
const hooksDir = join(pluginDir, "hooks");
|
|
182
|
+
try {
|
|
183
|
+
await mkdir(pluginDir, { recursive: true });
|
|
184
|
+
await mkdir(commandsDir, { recursive: true });
|
|
185
|
+
await mkdir(skillsDir, { recursive: true });
|
|
186
|
+
await mkdir(hooksDir, { recursive: true });
|
|
187
|
+
await writeFile(
|
|
188
|
+
join(pluginDir, "plugin.json"),
|
|
189
|
+
await formatJson(getPluginManifest(projectName))
|
|
190
|
+
);
|
|
191
|
+
await writeFile(join(commandsDir, "rapid-status.md"), COMMAND_RAPID_STATUS);
|
|
192
|
+
await writeFile(join(commandsDir, "rapid-worktree.md"), COMMAND_RAPID_WORKTREE);
|
|
193
|
+
await writeFile(join(commandsDir, "rapid-context.md"), COMMAND_RAPID_CONTEXT);
|
|
194
|
+
await writeFile(join(commandsDir, "rapid-mcp.md"), COMMAND_RAPID_MCP);
|
|
195
|
+
await writeFile(join(skillsDir, "rapid-methodology.md"), SKILL_RAPID_METHODOLOGY);
|
|
196
|
+
await writeFile(join(skillsDir, "mcp-usage.md"), SKILL_MCP_USAGE);
|
|
197
|
+
await writeFile(join(hooksDir, "hooks.json"), await formatJson(getHooksConfig()));
|
|
198
|
+
return true;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
logger.debug(
|
|
201
|
+
`Failed to create Claude plugin: ${error instanceof Error ? error.message : String(error)}`
|
|
202
|
+
);
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function getClaudePluginFiles() {
|
|
207
|
+
return [
|
|
208
|
+
".claude-plugin/plugin.json",
|
|
209
|
+
".claude-plugin/commands/rapid-status.md",
|
|
210
|
+
".claude-plugin/commands/rapid-worktree.md",
|
|
211
|
+
".claude-plugin/commands/rapid-context.md",
|
|
212
|
+
".claude-plugin/commands/rapid-mcp.md",
|
|
213
|
+
".claude-plugin/skills/rapid-methodology.md",
|
|
214
|
+
".claude-plugin/skills/mcp-usage.md",
|
|
215
|
+
".claude-plugin/hooks/hooks.json"
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/commands/init.ts
|
|
26
220
|
async function detectProjectType(dir) {
|
|
27
221
|
const files = await readdir(dir).catch(() => []);
|
|
28
222
|
const fileSet = new Set(files);
|
|
@@ -33,7 +227,7 @@ async function detectProjectType(dir) {
|
|
|
33
227
|
return { language: "go", confidence: "high" };
|
|
34
228
|
}
|
|
35
229
|
if (fileSet.has("pyproject.toml")) {
|
|
36
|
-
const content = await readFile(
|
|
230
|
+
const content = await readFile(join2(dir, "pyproject.toml"), "utf-8").catch(() => "");
|
|
37
231
|
const framework = content.includes("fastapi") ? "fastapi" : content.includes("django") ? "django" : content.includes("flask") ? "flask" : void 0;
|
|
38
232
|
if (framework) {
|
|
39
233
|
return { language: "python", framework, confidence: "high" };
|
|
@@ -53,7 +247,7 @@ async function detectProjectType(dir) {
|
|
|
53
247
|
const pkgManager = fileSet.has("pnpm-lock.yaml") ? "pnpm" : fileSet.has("yarn.lock") ? "yarn" : fileSet.has("bun.lockb") || fileSet.has("bun.lock") ? "bun" : "npm";
|
|
54
248
|
let framework;
|
|
55
249
|
if (fileSet.has("package.json")) {
|
|
56
|
-
const pkg = await readFile(
|
|
250
|
+
const pkg = await readFile(join2(dir, "package.json"), "utf-8").catch(() => "{}");
|
|
57
251
|
try {
|
|
58
252
|
const parsed = JSON.parse(pkg);
|
|
59
253
|
const deps = { ...parsed.dependencies, ...parsed.devDependencies };
|
|
@@ -80,7 +274,11 @@ async function detectProjectType(dir) {
|
|
|
80
274
|
}
|
|
81
275
|
if (fileSet.has("package.json")) {
|
|
82
276
|
const pkgManager = fileSet.has("pnpm-lock.yaml") ? "pnpm" : fileSet.has("yarn.lock") ? "yarn" : "npm";
|
|
83
|
-
return {
|
|
277
|
+
return {
|
|
278
|
+
language: "javascript",
|
|
279
|
+
packageManager: pkgManager,
|
|
280
|
+
confidence: "medium"
|
|
281
|
+
};
|
|
84
282
|
}
|
|
85
283
|
return { language: "unknown", confidence: "low" };
|
|
86
284
|
}
|
|
@@ -190,7 +388,7 @@ async function downloadRemoteTemplate(parsed, destDir, spinner) {
|
|
|
190
388
|
});
|
|
191
389
|
return true;
|
|
192
390
|
} catch (error) {
|
|
193
|
-
|
|
391
|
+
logger2.debug(
|
|
194
392
|
`Failed to download template: ${error instanceof Error ? error.message : String(error)}`
|
|
195
393
|
);
|
|
196
394
|
return false;
|
|
@@ -458,21 +656,21 @@ function getDevContainerConfig(detected, usePrebuilt = false) {
|
|
|
458
656
|
}
|
|
459
657
|
}
|
|
460
658
|
async function createDevContainer(dir, detected, force = false, usePrebuilt = false) {
|
|
461
|
-
const devcontainerDir =
|
|
462
|
-
const devcontainerJsonPath =
|
|
659
|
+
const devcontainerDir = join2(dir, ".devcontainer");
|
|
660
|
+
const devcontainerJsonPath = join2(devcontainerDir, "devcontainer.json");
|
|
463
661
|
if (!force && existsSync(devcontainerJsonPath)) {
|
|
464
662
|
return false;
|
|
465
663
|
}
|
|
466
|
-
await
|
|
664
|
+
await mkdir2(devcontainerDir, { recursive: true });
|
|
467
665
|
const config = getDevContainerConfig(detected, usePrebuilt);
|
|
468
|
-
await
|
|
666
|
+
await writeFile2(devcontainerJsonPath, await formatJson2(config));
|
|
469
667
|
return true;
|
|
470
668
|
}
|
|
471
|
-
var initCommand = new Command("init").description("Initialize RAPID in a project").argument("[template]", "Template: builtin name, github:user/repo, npm:package, or URL").option("--force", "Overwrite existing files", false).option("--agent <name>", "Default agent to configure", "claude").option("--no-devcontainer", "Skip devcontainer creation").option("--prebuilt", "Use pre-built devcontainer images from ghcr.io (faster startup)", false).option("--mcp <servers>", "MCP servers to enable (comma-separated)", "context7,tavily").option("--no-mcp", "Skip MCP server configuration").option("--no-detect", "Skip auto-detection of project type").action(async (templateArg, options) => {
|
|
669
|
+
var initCommand = new Command("init").description("Initialize RAPID in a project").argument("[template]", "Template: builtin name, github:user/repo, npm:package, or URL").option("--force", "Overwrite existing files", false).option("--agent <name>", "Default agent to configure", "claude").option("--no-devcontainer", "Skip devcontainer creation").option("--prebuilt", "Use pre-built devcontainer images from ghcr.io (faster startup)", false).option("--mcp <servers>", "MCP servers to enable (comma-separated)", "context7,tavily").option("--no-mcp", "Skip MCP server configuration").option("--no-detect", "Skip auto-detection of project type").option("--no-claude-plugin", "Skip Claude Code plugin generation").action(async (templateArg, options) => {
|
|
472
670
|
const spinner = ora("Initializing RAPID...").start();
|
|
473
671
|
try {
|
|
474
672
|
const cwd = process.cwd();
|
|
475
|
-
const configPath =
|
|
673
|
+
const configPath = join2(cwd, "rapid.json");
|
|
476
674
|
if (!options.force) {
|
|
477
675
|
try {
|
|
478
676
|
await access(configPath);
|
|
@@ -492,7 +690,7 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
|
|
|
492
690
|
`Detected ${detectedProject.language}${detectedProject.framework ? ` (${detectedProject.framework})` : ""} project`
|
|
493
691
|
);
|
|
494
692
|
templateSource = suggested;
|
|
495
|
-
|
|
693
|
+
logger2.info(`Using ${logger2.brand(suggested)} template`);
|
|
496
694
|
} else {
|
|
497
695
|
spinner.info("Could not detect project type, using universal template");
|
|
498
696
|
templateSource = "universal";
|
|
@@ -509,16 +707,16 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
|
|
|
509
707
|
const downloaded = await downloadRemoteTemplate(parsed, cwd, spinner);
|
|
510
708
|
if (!downloaded) {
|
|
511
709
|
spinner.fail(`Failed to download template from ${parsed.source}`);
|
|
512
|
-
|
|
513
|
-
|
|
710
|
+
logger2.info("Make sure the repository exists and is accessible.");
|
|
711
|
+
logger2.info("For private repos, set GIGET_AUTH environment variable.");
|
|
514
712
|
process.exit(1);
|
|
515
713
|
}
|
|
516
714
|
spinner.succeed(`Downloaded template from ${parsed.source}`);
|
|
517
715
|
try {
|
|
518
|
-
await access(
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
716
|
+
await access(join2(cwd, "rapid.json"));
|
|
717
|
+
logger2.blank();
|
|
718
|
+
logger2.info("Template includes rapid.json configuration.");
|
|
719
|
+
logger2.info("Run `rapid dev` to start coding!");
|
|
522
720
|
return;
|
|
523
721
|
} catch {
|
|
524
722
|
spinner.start("Creating RAPID configuration...");
|
|
@@ -532,7 +730,7 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
|
|
|
532
730
|
if (MCP_SERVER_TEMPLATES[serverName]) {
|
|
533
731
|
config = addMcpServerFromTemplate(config, serverName);
|
|
534
732
|
} else {
|
|
535
|
-
|
|
733
|
+
logger2.warn(`Unknown MCP server template: ${serverName}`);
|
|
536
734
|
}
|
|
537
735
|
}
|
|
538
736
|
const secretRefs = getSecretReferences(mcpServers);
|
|
@@ -549,7 +747,7 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
|
|
|
549
747
|
}
|
|
550
748
|
}
|
|
551
749
|
spinner.text = "Writing rapid.json...";
|
|
552
|
-
await
|
|
750
|
+
await writeFile2(configPath, await formatJson2(config));
|
|
553
751
|
if (mcpServers.length > 0) {
|
|
554
752
|
spinner.text = "Generating MCP configuration files...";
|
|
555
753
|
await writeMcpConfig(cwd, config);
|
|
@@ -557,12 +755,12 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
|
|
|
557
755
|
}
|
|
558
756
|
if (config.agents.available.claude) {
|
|
559
757
|
spinner.text = "Creating CLAUDE.md...";
|
|
560
|
-
const claudeMdPath =
|
|
561
|
-
await
|
|
758
|
+
const claudeMdPath = join2(cwd, "CLAUDE.md");
|
|
759
|
+
await writeFile2(claudeMdPath, getClaudeMdTemplate(cwd, detectedProject));
|
|
562
760
|
}
|
|
563
761
|
spinner.text = "Creating AGENTS.md...";
|
|
564
|
-
const agentsMdPath =
|
|
565
|
-
await
|
|
762
|
+
const agentsMdPath = join2(cwd, "AGENTS.md");
|
|
763
|
+
await writeFile2(agentsMdPath, getAgentsMdTemplate(cwd, detectedProject));
|
|
566
764
|
let devcontainerCreated = false;
|
|
567
765
|
const usePrebuilt = options.prebuilt === true;
|
|
568
766
|
if (options.devcontainer !== false) {
|
|
@@ -574,63 +772,75 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
|
|
|
574
772
|
usePrebuilt
|
|
575
773
|
);
|
|
576
774
|
}
|
|
775
|
+
let claudePluginCreated = false;
|
|
776
|
+
if (options.claudePlugin !== false && config.agents.available.claude) {
|
|
777
|
+
spinner.text = "Creating Claude Code plugin...";
|
|
778
|
+
const projectName = cwd.split("/").pop() || "project";
|
|
779
|
+
claudePluginCreated = await createClaudePlugin(cwd, projectName, { force: options.force });
|
|
780
|
+
}
|
|
577
781
|
spinner.succeed("RAPID initialized successfully!");
|
|
578
782
|
if (detectedProject && detectedProject.language !== "unknown") {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
console.log(` ${
|
|
783
|
+
logger2.blank();
|
|
784
|
+
logger2.info("Project detected:");
|
|
785
|
+
console.log(` ${logger2.dim("Language:")} ${detectedProject.language}`);
|
|
582
786
|
if (detectedProject.framework) {
|
|
583
|
-
console.log(` ${
|
|
787
|
+
console.log(` ${logger2.dim("Framework:")} ${detectedProject.framework}`);
|
|
584
788
|
}
|
|
585
789
|
if (detectedProject.packageManager) {
|
|
586
|
-
console.log(` ${
|
|
790
|
+
console.log(` ${logger2.dim("Package Mgr:")} ${detectedProject.packageManager}`);
|
|
587
791
|
}
|
|
588
792
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
console.log(` ${
|
|
793
|
+
logger2.blank();
|
|
794
|
+
logger2.info("Created files:");
|
|
795
|
+
console.log(` ${logger2.dim("\u2022")} rapid.json`);
|
|
592
796
|
if (mcpServers.length > 0) {
|
|
593
|
-
console.log(` ${
|
|
594
|
-
console.log(` ${
|
|
797
|
+
console.log(` ${logger2.dim("\u2022")} .mcp.json`);
|
|
798
|
+
console.log(` ${logger2.dim("\u2022")} opencode.json`);
|
|
595
799
|
}
|
|
596
800
|
if (devcontainerCreated) {
|
|
597
|
-
console.log(` ${
|
|
801
|
+
console.log(` ${logger2.dim("\u2022")} .devcontainer/devcontainer.json`);
|
|
802
|
+
}
|
|
803
|
+
if (claudePluginCreated) {
|
|
804
|
+
console.log(` ${logger2.dim("\u2022")} .claude-plugin/`);
|
|
805
|
+
for (const file of getClaudePluginFiles()) {
|
|
806
|
+
console.log(` ${logger2.dim("\u2022")} ${file.replace(".claude-plugin/", "")}`);
|
|
807
|
+
}
|
|
598
808
|
}
|
|
599
|
-
console.log(` ${
|
|
600
|
-
console.log(` ${
|
|
809
|
+
console.log(` ${logger2.dim("\u2022")} CLAUDE.md`);
|
|
810
|
+
console.log(` ${logger2.dim("\u2022")} AGENTS.md`);
|
|
601
811
|
if (mcpServers.length > 0) {
|
|
602
|
-
|
|
603
|
-
|
|
812
|
+
logger2.blank();
|
|
813
|
+
logger2.info("MCP servers configured:");
|
|
604
814
|
for (const serverName of mcpServers) {
|
|
605
815
|
const template = MCP_SERVER_TEMPLATES[serverName];
|
|
606
816
|
if (template) {
|
|
607
|
-
console.log(` ${
|
|
817
|
+
console.log(` ${logger2.brand("\u2022")} ${serverName} - ${template.description}`);
|
|
608
818
|
}
|
|
609
819
|
}
|
|
610
820
|
}
|
|
611
|
-
|
|
612
|
-
|
|
821
|
+
logger2.blank();
|
|
822
|
+
logger2.info("Next steps:");
|
|
613
823
|
let stepNum = 1;
|
|
614
824
|
console.log(
|
|
615
|
-
` ${
|
|
825
|
+
` ${logger2.dim(`${stepNum++}.`)} Run ${logger2.brand("rapid dev")} to start coding`
|
|
616
826
|
);
|
|
617
827
|
console.log(
|
|
618
|
-
` ${
|
|
828
|
+
` ${logger2.dim(`${stepNum++}.`)} Edit ${logger2.dim("rapid.json")} to customize your setup`
|
|
619
829
|
);
|
|
620
830
|
if (mcpServers.length > 0) {
|
|
621
831
|
console.log(
|
|
622
|
-
` ${
|
|
832
|
+
` ${logger2.dim(`${stepNum++}.`)} Add API keys to ${logger2.dim("secrets.items")} in rapid.json`
|
|
623
833
|
);
|
|
624
834
|
}
|
|
625
835
|
if (devcontainerCreated) {
|
|
626
836
|
console.log(
|
|
627
|
-
` ${
|
|
837
|
+
` ${logger2.dim(`${stepNum++}.`)} Set ${logger2.dim("OP_SERVICE_ACCOUNT_TOKEN")} env var for 1Password secrets`
|
|
628
838
|
);
|
|
629
839
|
}
|
|
630
|
-
|
|
840
|
+
logger2.blank();
|
|
631
841
|
} catch (error) {
|
|
632
842
|
spinner.fail("Failed to initialize RAPID");
|
|
633
|
-
|
|
843
|
+
logger2.error(error instanceof Error ? error.message : String(error));
|
|
634
844
|
process.exit(1);
|
|
635
845
|
}
|
|
636
846
|
});
|
|
@@ -746,13 +956,13 @@ ${GIT_GUIDELINES}
|
|
|
746
956
|
|
|
747
957
|
// src/commands/dev.ts
|
|
748
958
|
import { Command as Command2 } from "commander";
|
|
749
|
-
import { writeFile as
|
|
750
|
-
import { isAbsolute, join as
|
|
959
|
+
import { writeFile as writeFile4 } from "fs/promises";
|
|
960
|
+
import { isAbsolute, join as join5 } from "path";
|
|
751
961
|
import {
|
|
752
962
|
loadConfig,
|
|
753
963
|
getAgent,
|
|
754
964
|
checkAgentAvailable,
|
|
755
|
-
logger as
|
|
965
|
+
logger as logger3,
|
|
756
966
|
getContainerStatus,
|
|
757
967
|
startContainer,
|
|
758
968
|
execInContainer,
|
|
@@ -763,14 +973,17 @@ import {
|
|
|
763
973
|
hasVaultCli,
|
|
764
974
|
isVaultAuthenticated,
|
|
765
975
|
buildAgentArgs,
|
|
766
|
-
agentSupportsRuntimeInjection
|
|
976
|
+
agentSupportsRuntimeInjection,
|
|
977
|
+
formatJson as formatJson3,
|
|
978
|
+
assembleContext,
|
|
979
|
+
generateMcpConfig
|
|
767
980
|
} from "@a3t/rapid-core";
|
|
768
981
|
import ora2 from "ora";
|
|
769
982
|
|
|
770
983
|
// src/utils/worktree.ts
|
|
771
984
|
import { execa } from "execa";
|
|
772
985
|
import { access as access2 } from "fs/promises";
|
|
773
|
-
import { basename, dirname, join as
|
|
986
|
+
import { basename, dirname, join as join3, resolve } from "path";
|
|
774
987
|
function getErrorMessage(err) {
|
|
775
988
|
if (typeof err.stderr === "string" && err.stderr) {
|
|
776
989
|
return err.stderr;
|
|
@@ -880,7 +1093,7 @@ function generateWorktreePath(repoRoot, branchName) {
|
|
|
880
1093
|
const projectName = basename(repoRoot);
|
|
881
1094
|
const parentDir = dirname(repoRoot);
|
|
882
1095
|
const safeBranchName = branchName.replace(/\//g, "-").replace(/[^a-zA-Z0-9-_]/g, "").toLowerCase();
|
|
883
|
-
return
|
|
1096
|
+
return join3(parentDir, `${projectName}-${safeBranchName}`);
|
|
884
1097
|
}
|
|
885
1098
|
async function createWorktree(repoRoot, worktreePath, branch, options = {}) {
|
|
886
1099
|
try {
|
|
@@ -991,9 +1204,9 @@ async function cleanupMergedWorktrees(repoRoot) {
|
|
|
991
1204
|
|
|
992
1205
|
// src/isolation/lima.ts
|
|
993
1206
|
import { execa as execa2 } from "execa";
|
|
994
|
-
import { readFile as readFile2, writeFile as
|
|
1207
|
+
import { readFile as readFile2, writeFile as writeFile3, mkdir as mkdir3, access as access3 } from "fs/promises";
|
|
995
1208
|
import { homedir, platform } from "os";
|
|
996
|
-
import { join as
|
|
1209
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
997
1210
|
import { fileURLToPath } from "url";
|
|
998
1211
|
function getErrorMessage2(err) {
|
|
999
1212
|
if (typeof err.stderr === "string" && err.stderr) {
|
|
@@ -1008,7 +1221,7 @@ function getOutputString(output) {
|
|
|
1008
1221
|
return void 0;
|
|
1009
1222
|
}
|
|
1010
1223
|
var RAPID_LIMA_INSTANCE = "rapid";
|
|
1011
|
-
var RAPID_LIMA_DIR =
|
|
1224
|
+
var RAPID_LIMA_DIR = join4(homedir(), ".rapid", "lima");
|
|
1012
1225
|
async function hasLima() {
|
|
1013
1226
|
try {
|
|
1014
1227
|
await execa2("limactl", ["--version"]);
|
|
@@ -1023,11 +1236,11 @@ function isMacOS() {
|
|
|
1023
1236
|
function getLimaTemplatePath() {
|
|
1024
1237
|
const __dirname3 = dirname2(fileURLToPath(import.meta.url));
|
|
1025
1238
|
const possiblePaths = [
|
|
1026
|
-
|
|
1239
|
+
join4(__dirname3, "../../../../templates/lima.yaml"),
|
|
1027
1240
|
// From dist/isolation/
|
|
1028
|
-
|
|
1241
|
+
join4(__dirname3, "../../../templates/lima.yaml"),
|
|
1029
1242
|
// From src/isolation/
|
|
1030
|
-
|
|
1243
|
+
join4(homedir(), ".rapid", "lima.yaml")
|
|
1031
1244
|
// User config
|
|
1032
1245
|
];
|
|
1033
1246
|
return possiblePaths[0];
|
|
@@ -1067,7 +1280,7 @@ async function instanceExists(name = RAPID_LIMA_INSTANCE) {
|
|
|
1067
1280
|
return instanceDirExists(name);
|
|
1068
1281
|
}
|
|
1069
1282
|
async function instanceDirExists(name = RAPID_LIMA_INSTANCE) {
|
|
1070
|
-
const instanceDir =
|
|
1283
|
+
const instanceDir = join4(homedir(), ".lima", name);
|
|
1071
1284
|
try {
|
|
1072
1285
|
await access3(instanceDir);
|
|
1073
1286
|
return true;
|
|
@@ -1092,8 +1305,8 @@ ${homeMount}${projectMount}`;
|
|
|
1092
1305
|
async function createLimaConfig(projectDir, options = {}) {
|
|
1093
1306
|
const templatePath = getLimaTemplatePath();
|
|
1094
1307
|
const configDir = RAPID_LIMA_DIR;
|
|
1095
|
-
const configPath =
|
|
1096
|
-
await
|
|
1308
|
+
const configPath = join4(configDir, "lima.yaml");
|
|
1309
|
+
await mkdir3(configDir, { recursive: true });
|
|
1097
1310
|
let template;
|
|
1098
1311
|
try {
|
|
1099
1312
|
template = await readFile2(templatePath, "utf-8");
|
|
@@ -1117,7 +1330,11 @@ async function createLimaConfig(projectDir, options = {}) {
|
|
|
1117
1330
|
${envLines}
|
|
1118
1331
|
`);
|
|
1119
1332
|
}
|
|
1120
|
-
|
|
1333
|
+
if (options.installGh === false) {
|
|
1334
|
+
const ghInstallPattern = /\s*# Install GitHub CLI\n\s*curl -fsSL https:\/\/cli\.github\.com\/packages\/githubcli-archive-keyring\.gpg \| dd of=\/usr\/share\/keyrings\/githubcli-archive-keyring\.gpg\n\s*chmod go\+r \/usr\/share\/keyrings\/githubcli-archive-keyring\.gpg\n\s*echo "deb \[arch=\$\(dpkg --print-architecture\) signed-by=\/usr\/share\/keyrings\/githubcli-archive-keyring\.gpg\] https:\/\/cli\.github\.com\/packages stable main" \| tee \/etc\/apt\/sources\.list\.d\/github-cli\.list > \/dev\/null\n\s*apt-get update\n\s*apt-get install -y gh\n/;
|
|
1335
|
+
config = config.replace(ghInstallPattern, "\n");
|
|
1336
|
+
}
|
|
1337
|
+
await writeFile3(configPath, config);
|
|
1121
1338
|
return configPath;
|
|
1122
1339
|
}
|
|
1123
1340
|
function getMinimalLimaConfig() {
|
|
@@ -1298,6 +1515,56 @@ async function shellInLima(options = {}) {
|
|
|
1298
1515
|
}
|
|
1299
1516
|
await execa2("limactl", args, { stdio: "inherit" });
|
|
1300
1517
|
}
|
|
1518
|
+
var AGENT_INSTALL_COMMANDS = {
|
|
1519
|
+
claude: ["sudo", "npm", "install", "-g", "@anthropic-ai/claude-code"],
|
|
1520
|
+
opencode: ["bash", "-c", "curl -fsSL https://opencode.ai/install | bash"],
|
|
1521
|
+
aider: ["pip3", "install", "--user", "aider-chat"]
|
|
1522
|
+
};
|
|
1523
|
+
async function isAgentInstalled(agentCli, name = RAPID_LIMA_INSTANCE) {
|
|
1524
|
+
try {
|
|
1525
|
+
const result = await execInLima(["which", agentCli], { name });
|
|
1526
|
+
return result.success && !!result.stdout?.trim();
|
|
1527
|
+
} catch {
|
|
1528
|
+
return false;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
async function installAgent(agentCli, name = RAPID_LIMA_INSTANCE) {
|
|
1532
|
+
const installCmd = AGENT_INSTALL_COMMANDS[agentCli];
|
|
1533
|
+
if (!installCmd) {
|
|
1534
|
+
return {
|
|
1535
|
+
success: false,
|
|
1536
|
+
error: `Unknown agent "${agentCli}". No install command available.`
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
try {
|
|
1540
|
+
const result = await execInLima(installCmd, { name });
|
|
1541
|
+
if (!result.success) {
|
|
1542
|
+
return {
|
|
1543
|
+
success: false,
|
|
1544
|
+
error: result.error || result.stderr || `Failed to install ${agentCli}`
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
const installed = await isAgentInstalled(agentCli, name);
|
|
1548
|
+
if (!installed) {
|
|
1549
|
+
return {
|
|
1550
|
+
success: false,
|
|
1551
|
+
error: `Installation command succeeded but ${agentCli} is not in PATH`
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
return { success: true };
|
|
1555
|
+
} catch (err) {
|
|
1556
|
+
return {
|
|
1557
|
+
success: false,
|
|
1558
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
async function ensureAgentInstalled(agentCli, name = RAPID_LIMA_INSTANCE) {
|
|
1563
|
+
if (await isAgentInstalled(agentCli, name)) {
|
|
1564
|
+
return { success: true };
|
|
1565
|
+
}
|
|
1566
|
+
return installAgent(agentCli, name);
|
|
1567
|
+
}
|
|
1301
1568
|
async function setupGitSsh(name = RAPID_LIMA_INSTANCE) {
|
|
1302
1569
|
try {
|
|
1303
1570
|
const result = await execInLima(["ssh-add", "-l"], { name });
|
|
@@ -1352,7 +1619,7 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1352
1619
|
}
|
|
1353
1620
|
} catch (err) {
|
|
1354
1621
|
spinner.warn("Could not create worktree, using main directory");
|
|
1355
|
-
|
|
1622
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1356
1623
|
}
|
|
1357
1624
|
}
|
|
1358
1625
|
}
|
|
@@ -1363,8 +1630,8 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1363
1630
|
const agentName = options.agent || config.agents.default;
|
|
1364
1631
|
const agent = getAgent(config, agentName);
|
|
1365
1632
|
if (!agent) {
|
|
1366
|
-
|
|
1367
|
-
|
|
1633
|
+
logger3.error(`Agent "${agentName}" not found in configuration`);
|
|
1634
|
+
logger3.info("Available agents:");
|
|
1368
1635
|
Object.keys(config.agents.available).forEach((name) => {
|
|
1369
1636
|
const isDefault = name === config.agents.default;
|
|
1370
1637
|
console.log(` ${isDefault ? "* " : " "}${name}${isDefault ? " (default)" : ""}`);
|
|
@@ -1372,18 +1639,18 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1372
1639
|
process.exit(1);
|
|
1373
1640
|
}
|
|
1374
1641
|
if (options.local) {
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1642
|
+
logger3.warn("Running locally instead of in container");
|
|
1643
|
+
logger3.dim("This bypasses the isolated dev environment");
|
|
1644
|
+
logger3.blank();
|
|
1378
1645
|
await runLocally(agent, agentName, rootDir, config);
|
|
1379
1646
|
return;
|
|
1380
1647
|
}
|
|
1381
1648
|
const hasDevCli = await hasDevcontainerCli();
|
|
1382
1649
|
if (!hasDevCli) {
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1650
|
+
logger3.error("devcontainer CLI not found");
|
|
1651
|
+
logger3.info("Install with: npm install -g @devcontainers/cli");
|
|
1652
|
+
logger3.blank();
|
|
1653
|
+
logger3.info("Or use --local to run without container (not recommended)");
|
|
1387
1654
|
process.exit(1);
|
|
1388
1655
|
}
|
|
1389
1656
|
spinner.start("Checking container status...");
|
|
@@ -1397,12 +1664,12 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1397
1664
|
spinner.stopAndPersist({ symbol: "\u{1F433}", text: "Starting container..." });
|
|
1398
1665
|
const result = await startContainer(rootDir, config, { quiet: false });
|
|
1399
1666
|
if (!result.success) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1667
|
+
logger3.blank();
|
|
1668
|
+
logger3.error("Failed to start container");
|
|
1669
|
+
logger3.error(result.error || "Unknown error");
|
|
1403
1670
|
process.exit(1);
|
|
1404
1671
|
}
|
|
1405
|
-
|
|
1672
|
+
logger3.blank();
|
|
1406
1673
|
} else {
|
|
1407
1674
|
spinner.succeed(`Container running (${status.containerName})`);
|
|
1408
1675
|
}
|
|
@@ -1415,12 +1682,12 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1415
1682
|
const hasOp = await hasOpCli();
|
|
1416
1683
|
if (!hasOp) {
|
|
1417
1684
|
spinner.warn("1Password CLI not found - secrets will not be loaded");
|
|
1418
|
-
|
|
1685
|
+
logger3.info("Install with: brew install 1password-cli");
|
|
1419
1686
|
} else {
|
|
1420
1687
|
const authenticated = await isOpAuthenticated();
|
|
1421
1688
|
if (!authenticated) {
|
|
1422
1689
|
spinner.warn("1Password not authenticated - secrets will not be loaded");
|
|
1423
|
-
|
|
1690
|
+
logger3.info("Run: eval $(op signin)");
|
|
1424
1691
|
} else {
|
|
1425
1692
|
try {
|
|
1426
1693
|
secrets = await loadSecrets(secretsConfig);
|
|
@@ -1428,7 +1695,7 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1428
1695
|
spinner.succeed(`Loaded ${count} secret${count !== 1 ? "s" : ""} from 1Password`);
|
|
1429
1696
|
} catch (err) {
|
|
1430
1697
|
spinner.warn("Failed to load secrets from 1Password");
|
|
1431
|
-
|
|
1698
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1432
1699
|
}
|
|
1433
1700
|
}
|
|
1434
1701
|
}
|
|
@@ -1437,12 +1704,12 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1437
1704
|
const hasVault = await hasVaultCli();
|
|
1438
1705
|
if (!hasVault) {
|
|
1439
1706
|
spinner.warn("Vault CLI not found - secrets will not be loaded");
|
|
1440
|
-
|
|
1707
|
+
logger3.info("Install from: https://developer.hashicorp.com/vault/docs/install");
|
|
1441
1708
|
} else {
|
|
1442
1709
|
const authenticated = await isVaultAuthenticated();
|
|
1443
1710
|
if (!authenticated) {
|
|
1444
1711
|
spinner.warn("Vault not authenticated - secrets will not be loaded");
|
|
1445
|
-
|
|
1712
|
+
logger3.info("Run: vault login");
|
|
1446
1713
|
} else {
|
|
1447
1714
|
try {
|
|
1448
1715
|
secrets = await loadSecrets(secretsConfig);
|
|
@@ -1450,7 +1717,7 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1450
1717
|
spinner.succeed(`Loaded ${count} secret${count !== 1 ? "s" : ""} from Vault`);
|
|
1451
1718
|
} catch (err) {
|
|
1452
1719
|
spinner.warn("Failed to load secrets from Vault");
|
|
1453
|
-
|
|
1720
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1454
1721
|
}
|
|
1455
1722
|
}
|
|
1456
1723
|
}
|
|
@@ -1466,17 +1733,44 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1466
1733
|
}
|
|
1467
1734
|
} catch (err) {
|
|
1468
1735
|
spinner.warn("Failed to load secrets from environment");
|
|
1469
|
-
|
|
1736
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1470
1737
|
}
|
|
1471
1738
|
}
|
|
1472
1739
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1740
|
+
let contextContent;
|
|
1741
|
+
if (config.context?.files?.length || config.context?.dirs?.length) {
|
|
1742
|
+
const spinner2 = ora2("Assembling context files...").start();
|
|
1743
|
+
try {
|
|
1744
|
+
const assembled = await assembleContext(rootDir, config.context);
|
|
1745
|
+
if (assembled.files.length > 0) {
|
|
1746
|
+
contextContent = assembled.content;
|
|
1747
|
+
spinner2.succeed(
|
|
1748
|
+
`Assembled ${assembled.files.length} context file${assembled.files.length !== 1 ? "s" : ""} (${Math.round(assembled.totalSize / 1024)}KB)`
|
|
1749
|
+
);
|
|
1750
|
+
if (assembled.skippedFiles.length > 0) {
|
|
1751
|
+
logger3.dim(` Skipped ${assembled.skippedFiles.length} file(s)`);
|
|
1752
|
+
}
|
|
1753
|
+
} else {
|
|
1754
|
+
spinner2.warn("No context files found");
|
|
1755
|
+
}
|
|
1756
|
+
} catch (err) {
|
|
1757
|
+
spinner2.warn("Failed to assemble context files");
|
|
1758
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
logger3.blank();
|
|
1762
|
+
logger3.info(`Launching ${logger3.brand(agentName)} in container...`);
|
|
1763
|
+
const builtArgs = buildAgentArgs(agent, {
|
|
1764
|
+
injectSystemPrompt: true,
|
|
1765
|
+
...contextContent && { contextContent }
|
|
1766
|
+
});
|
|
1476
1767
|
if (agentSupportsRuntimeInjection(agent)) {
|
|
1477
|
-
|
|
1768
|
+
logger3.dim("Injecting RAPID methodology via CLI args");
|
|
1769
|
+
if (contextContent) {
|
|
1770
|
+
logger3.dim("Injecting context files via CLI args");
|
|
1771
|
+
}
|
|
1478
1772
|
}
|
|
1479
|
-
|
|
1773
|
+
logger3.blank();
|
|
1480
1774
|
const agentArgs = [agent.cli, ...builtArgs];
|
|
1481
1775
|
const mcpEnv = await prepareMcpEnv(rootDir, config.mcp);
|
|
1482
1776
|
const mergedEnv = { ...secrets, ...mcpEnv ?? {} };
|
|
@@ -1486,7 +1780,7 @@ var devCommand = new Command2("dev").description("Launch AI coding session in th
|
|
|
1486
1780
|
env: mergedEnv
|
|
1487
1781
|
});
|
|
1488
1782
|
} catch (error) {
|
|
1489
|
-
|
|
1783
|
+
logger3.error(error instanceof Error ? error.message : String(error));
|
|
1490
1784
|
process.exit(1);
|
|
1491
1785
|
}
|
|
1492
1786
|
});
|
|
@@ -1495,24 +1789,16 @@ async function prepareMcpEnv(rootDir, mcp) {
|
|
|
1495
1789
|
return void 0;
|
|
1496
1790
|
}
|
|
1497
1791
|
const configFile = mcp.configFile ?? ".mcp.json";
|
|
1498
|
-
const configPath = isAbsolute(configFile) ? configFile :
|
|
1499
|
-
const
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
if (enabled === false) {
|
|
1506
|
-
continue;
|
|
1507
|
-
}
|
|
1508
|
-
const outputType = type === "remote" ? "http" : type;
|
|
1509
|
-
mcpServers[name] = { type: outputType, ...rest };
|
|
1510
|
-
}
|
|
1511
|
-
if (Object.keys(mcpServers).length === 0) {
|
|
1792
|
+
const configPath = isAbsolute(configFile) ? configFile : join5(rootDir, configFile);
|
|
1793
|
+
const mcpConfig = generateMcpConfig({
|
|
1794
|
+
version: "1.0",
|
|
1795
|
+
agents: { default: "", available: {} },
|
|
1796
|
+
mcp
|
|
1797
|
+
});
|
|
1798
|
+
if (Object.keys(mcpConfig.mcpServers).length === 0) {
|
|
1512
1799
|
return void 0;
|
|
1513
1800
|
}
|
|
1514
|
-
await
|
|
1515
|
-
`, "utf-8");
|
|
1801
|
+
await writeFile4(configPath, await formatJson3(mcpConfig), "utf-8");
|
|
1516
1802
|
return {
|
|
1517
1803
|
MCP_CONFIG_FILE: configFile
|
|
1518
1804
|
};
|
|
@@ -1521,7 +1807,7 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1521
1807
|
const { execa: execa4 } = await import("execa");
|
|
1522
1808
|
const status = await checkAgentAvailable(agent);
|
|
1523
1809
|
if (!status.available) {
|
|
1524
|
-
|
|
1810
|
+
logger3.error(`${agentName} CLI not found locally`);
|
|
1525
1811
|
process.exit(1);
|
|
1526
1812
|
}
|
|
1527
1813
|
let secrets = {};
|
|
@@ -1534,12 +1820,12 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1534
1820
|
const hasOp = await hasOpCli();
|
|
1535
1821
|
if (!hasOp) {
|
|
1536
1822
|
spinner.warn("1Password CLI not found - secrets will not be loaded");
|
|
1537
|
-
|
|
1823
|
+
logger3.info("Install with: brew install 1password-cli");
|
|
1538
1824
|
} else {
|
|
1539
1825
|
const authenticated = await isOpAuthenticated();
|
|
1540
1826
|
if (!authenticated) {
|
|
1541
1827
|
spinner.warn("1Password not authenticated - secrets will not be loaded");
|
|
1542
|
-
|
|
1828
|
+
logger3.info("Run: eval $(op signin)");
|
|
1543
1829
|
} else {
|
|
1544
1830
|
try {
|
|
1545
1831
|
secrets = await loadSecrets(secretsConfig);
|
|
@@ -1547,7 +1833,7 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1547
1833
|
spinner.succeed(`Loaded ${count} secret${count !== 1 ? "s" : ""} from 1Password`);
|
|
1548
1834
|
} catch (err) {
|
|
1549
1835
|
spinner.warn("Failed to load secrets from 1Password");
|
|
1550
|
-
|
|
1836
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1551
1837
|
}
|
|
1552
1838
|
}
|
|
1553
1839
|
}
|
|
@@ -1556,12 +1842,12 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1556
1842
|
const hasVault = await hasVaultCli();
|
|
1557
1843
|
if (!hasVault) {
|
|
1558
1844
|
spinner.warn("Vault CLI not found - secrets will not be loaded");
|
|
1559
|
-
|
|
1845
|
+
logger3.info("Install from: https://developer.hashicorp.com/vault/docs/install");
|
|
1560
1846
|
} else {
|
|
1561
1847
|
const authenticated = await isVaultAuthenticated();
|
|
1562
1848
|
if (!authenticated) {
|
|
1563
1849
|
spinner.warn("Vault not authenticated - secrets will not be loaded");
|
|
1564
|
-
|
|
1850
|
+
logger3.info("Run: vault login");
|
|
1565
1851
|
} else {
|
|
1566
1852
|
try {
|
|
1567
1853
|
secrets = await loadSecrets(secretsConfig);
|
|
@@ -1569,7 +1855,7 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1569
1855
|
spinner.succeed(`Loaded ${count} secret${count !== 1 ? "s" : ""} from Vault`);
|
|
1570
1856
|
} catch (err) {
|
|
1571
1857
|
spinner.warn("Failed to load secrets from Vault");
|
|
1572
|
-
|
|
1858
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1573
1859
|
}
|
|
1574
1860
|
}
|
|
1575
1861
|
}
|
|
@@ -1585,23 +1871,50 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1585
1871
|
}
|
|
1586
1872
|
} catch (err) {
|
|
1587
1873
|
spinner.warn("Failed to load secrets from environment");
|
|
1588
|
-
|
|
1874
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1589
1875
|
}
|
|
1590
1876
|
}
|
|
1591
1877
|
}
|
|
1592
1878
|
const mcpEnv = await prepareMcpEnv(rootDir, config.mcp);
|
|
1593
1879
|
const mergedEnv = { ...secrets, ...mcpEnv ?? {} };
|
|
1594
|
-
|
|
1880
|
+
let contextContent;
|
|
1881
|
+
if (config.context?.files?.length || config.context?.dirs?.length) {
|
|
1882
|
+
const spinner = ora2("Assembling context files...").start();
|
|
1883
|
+
try {
|
|
1884
|
+
const assembled = await assembleContext(rootDir, config.context);
|
|
1885
|
+
if (assembled.files.length > 0) {
|
|
1886
|
+
contextContent = assembled.content;
|
|
1887
|
+
spinner.succeed(
|
|
1888
|
+
`Assembled ${assembled.files.length} context file${assembled.files.length !== 1 ? "s" : ""} (${Math.round(assembled.totalSize / 1024)}KB)`
|
|
1889
|
+
);
|
|
1890
|
+
if (assembled.skippedFiles.length > 0) {
|
|
1891
|
+
logger3.dim(` Skipped ${assembled.skippedFiles.length} file(s)`);
|
|
1892
|
+
}
|
|
1893
|
+
} else {
|
|
1894
|
+
spinner.warn("No context files found");
|
|
1895
|
+
}
|
|
1896
|
+
} catch (err) {
|
|
1897
|
+
spinner.warn("Failed to assemble context files");
|
|
1898
|
+
logger3.debug(err instanceof Error ? err.message : String(err));
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
const builtArgs = buildAgentArgs(agent, {
|
|
1902
|
+
injectSystemPrompt: true,
|
|
1903
|
+
...contextContent && { contextContent }
|
|
1904
|
+
});
|
|
1595
1905
|
if (isMacOS() && await hasLima()) {
|
|
1596
|
-
await runInLimaVm(agent, agentName, rootDir, builtArgs, mergedEnv);
|
|
1906
|
+
await runInLimaVm(agent, agentName, rootDir, builtArgs, mergedEnv, config.lima);
|
|
1597
1907
|
return;
|
|
1598
1908
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1909
|
+
logger3.info(`Launching ${logger3.brand(agentName)}...`);
|
|
1910
|
+
logger3.dim(`Working directory: ${rootDir}`);
|
|
1601
1911
|
if (agentSupportsRuntimeInjection(agent)) {
|
|
1602
|
-
|
|
1912
|
+
logger3.dim("Injecting RAPID methodology via CLI args");
|
|
1913
|
+
if (contextContent) {
|
|
1914
|
+
logger3.dim("Injecting context files via CLI args");
|
|
1915
|
+
}
|
|
1603
1916
|
}
|
|
1604
|
-
|
|
1917
|
+
logger3.blank();
|
|
1605
1918
|
await execa4(agent.cli, builtArgs, {
|
|
1606
1919
|
cwd: rootDir,
|
|
1607
1920
|
stdio: "inherit",
|
|
@@ -1611,21 +1924,22 @@ async function runLocally(agent, agentName, rootDir, config) {
|
|
|
1611
1924
|
}
|
|
1612
1925
|
});
|
|
1613
1926
|
}
|
|
1614
|
-
async function runInLimaVm(agent, agentName, rootDir, args, env) {
|
|
1927
|
+
async function runInLimaVm(agent, agentName, rootDir, args, env, limaConfig) {
|
|
1615
1928
|
const spinner = ora2();
|
|
1616
1929
|
if (!await isRunning()) {
|
|
1617
1930
|
spinner.start(`Starting Lima VM (${RAPID_LIMA_INSTANCE})...`);
|
|
1618
1931
|
const result = await startInstance(rootDir, {
|
|
1619
1932
|
env,
|
|
1620
|
-
timeout: 600
|
|
1933
|
+
timeout: 600,
|
|
1621
1934
|
// 10 minutes for first-time setup
|
|
1935
|
+
...limaConfig?.installGh !== void 0 && { installGh: limaConfig.installGh }
|
|
1622
1936
|
});
|
|
1623
1937
|
if (!result.success) {
|
|
1624
1938
|
spinner.fail("Failed to start Lima VM");
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1939
|
+
logger3.error(result.error ?? "Unknown error");
|
|
1940
|
+
logger3.blank();
|
|
1941
|
+
logger3.info("Falling back to running directly on host...");
|
|
1942
|
+
logger3.blank();
|
|
1629
1943
|
const { execa: execa4 } = await import("execa");
|
|
1630
1944
|
await execa4(agent.cli, args, {
|
|
1631
1945
|
cwd: rootDir,
|
|
@@ -1639,12 +1953,32 @@ async function runInLimaVm(agent, agentName, rootDir, args, env) {
|
|
|
1639
1953
|
}
|
|
1640
1954
|
spinner.succeed("Lima VM started");
|
|
1641
1955
|
} else {
|
|
1642
|
-
|
|
1956
|
+
logger3.info(`Lima VM (${RAPID_LIMA_INSTANCE}) is running`);
|
|
1957
|
+
}
|
|
1958
|
+
spinner.start(`Checking if ${agentName} is installed in Lima VM...`);
|
|
1959
|
+
const installResult = await ensureAgentInstalled(agent.cli);
|
|
1960
|
+
if (!installResult.success) {
|
|
1961
|
+
spinner.fail(`Failed to install ${agentName} in Lima VM`);
|
|
1962
|
+
logger3.error(installResult.error ?? "Unknown error");
|
|
1963
|
+
logger3.blank();
|
|
1964
|
+
logger3.info("Falling back to running directly on host...");
|
|
1965
|
+
logger3.blank();
|
|
1966
|
+
const { execa: execa4 } = await import("execa");
|
|
1967
|
+
await execa4(agent.cli, args, {
|
|
1968
|
+
cwd: rootDir,
|
|
1969
|
+
stdio: "inherit",
|
|
1970
|
+
env: {
|
|
1971
|
+
...process.env,
|
|
1972
|
+
...env
|
|
1973
|
+
}
|
|
1974
|
+
});
|
|
1975
|
+
return;
|
|
1643
1976
|
}
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1977
|
+
spinner.succeed(`${agentName} is available in Lima VM`);
|
|
1978
|
+
logger3.info(`Launching ${logger3.brand(agentName)} in Lima VM...`);
|
|
1979
|
+
logger3.dim(`Working directory: ${rootDir}`);
|
|
1980
|
+
logger3.dim("SSH agent forwarded for commit signing");
|
|
1981
|
+
logger3.blank();
|
|
1648
1982
|
await execInLima([agent.cli, ...args], {
|
|
1649
1983
|
cwd: rootDir,
|
|
1650
1984
|
env,
|
|
@@ -1653,20 +1987,20 @@ async function runInLimaVm(agent, agentName, rootDir, args, env) {
|
|
|
1653
1987
|
});
|
|
1654
1988
|
}
|
|
1655
1989
|
function listAgents(config) {
|
|
1656
|
-
|
|
1990
|
+
logger3.header("Available Agents");
|
|
1657
1991
|
Object.keys(config.agents.available).forEach((name) => {
|
|
1658
1992
|
const isDefault = name === config.agents.default;
|
|
1659
1993
|
console.log(
|
|
1660
|
-
` ${isDefault ?
|
|
1994
|
+
` ${isDefault ? logger3.brand("*") : " "} ${name}${isDefault ? logger3.dim(" (default)") : ""}`
|
|
1661
1995
|
);
|
|
1662
1996
|
});
|
|
1663
|
-
|
|
1664
|
-
|
|
1997
|
+
logger3.blank();
|
|
1998
|
+
logger3.dim("Use --agent <name> to select a specific agent");
|
|
1665
1999
|
}
|
|
1666
2000
|
async function runMultiAgent(config, rootDir, options) {
|
|
1667
2001
|
const availableAgents = Object.keys(config.agents.available);
|
|
1668
2002
|
if (availableAgents.length === 0) {
|
|
1669
|
-
|
|
2003
|
+
logger3.error("No agents configured");
|
|
1670
2004
|
process.exit(1);
|
|
1671
2005
|
}
|
|
1672
2006
|
let selectedAgents;
|
|
@@ -1674,48 +2008,48 @@ async function runMultiAgent(config, rootDir, options) {
|
|
|
1674
2008
|
selectedAgents = options.multi.split(",").map((a) => a.trim()).filter(Boolean);
|
|
1675
2009
|
for (const name of selectedAgents) {
|
|
1676
2010
|
if (!config.agents.available[name]) {
|
|
1677
|
-
|
|
1678
|
-
|
|
2011
|
+
logger3.error(`Agent "${name}" not found in configuration`);
|
|
2012
|
+
logger3.info("Available agents: " + availableAgents.join(", "));
|
|
1679
2013
|
process.exit(1);
|
|
1680
2014
|
}
|
|
1681
2015
|
}
|
|
1682
2016
|
} else {
|
|
1683
|
-
|
|
2017
|
+
logger3.header("Multi-Agent Mode");
|
|
1684
2018
|
console.log();
|
|
1685
2019
|
console.log(" Available agents:");
|
|
1686
2020
|
for (const name of availableAgents) {
|
|
1687
2021
|
const isDefault = name === config.agents.default;
|
|
1688
|
-
console.log(` ${
|
|
2022
|
+
console.log(` ${logger3.brand("\u2022")} ${name}${isDefault ? logger3.dim(" (default)") : ""}`);
|
|
1689
2023
|
}
|
|
1690
2024
|
console.log();
|
|
1691
|
-
|
|
1692
|
-
console.log(` ${
|
|
2025
|
+
logger3.info("To run multiple agents, specify them with:");
|
|
2026
|
+
console.log(` ${logger3.brand("rapid dev --multi claude,aider")}`);
|
|
1693
2027
|
console.log();
|
|
1694
|
-
|
|
2028
|
+
logger3.info("Or run agents in separate terminals:");
|
|
1695
2029
|
for (const name of availableAgents) {
|
|
1696
|
-
console.log(` ${
|
|
2030
|
+
console.log(` ${logger3.dim("$")} rapid dev --agent ${name}`);
|
|
1697
2031
|
}
|
|
1698
2032
|
console.log();
|
|
1699
|
-
|
|
1700
|
-
|
|
2033
|
+
logger3.warn("Note: Running multiple agents simultaneously requires separate terminal windows.");
|
|
2034
|
+
logger3.info("Each agent maintains its own session and context.");
|
|
1701
2035
|
console.log();
|
|
1702
2036
|
return;
|
|
1703
2037
|
}
|
|
1704
2038
|
if (selectedAgents.length === 0) {
|
|
1705
|
-
|
|
2039
|
+
logger3.error("No agents specified");
|
|
1706
2040
|
process.exit(1);
|
|
1707
2041
|
}
|
|
1708
2042
|
if (selectedAgents.length === 1) {
|
|
1709
|
-
|
|
1710
|
-
`Only one agent specified. Use ${
|
|
2043
|
+
logger3.info(
|
|
2044
|
+
`Only one agent specified. Use ${logger3.brand("rapid dev --agent " + selectedAgents[0])} instead.`
|
|
1711
2045
|
);
|
|
1712
2046
|
process.exit(0);
|
|
1713
2047
|
}
|
|
1714
|
-
|
|
2048
|
+
logger3.header("Multi-Agent Session");
|
|
1715
2049
|
console.log();
|
|
1716
2050
|
console.log(" Selected agents:");
|
|
1717
2051
|
for (const name of selectedAgents) {
|
|
1718
|
-
console.log(` ${
|
|
2052
|
+
console.log(` ${logger3.brand("\u2022")} ${name}`);
|
|
1719
2053
|
}
|
|
1720
2054
|
console.log();
|
|
1721
2055
|
const { execa: execa4 } = await import("execa");
|
|
@@ -1727,7 +2061,7 @@ async function runMultiAgent(config, rootDir, options) {
|
|
|
1727
2061
|
hasTmux = false;
|
|
1728
2062
|
}
|
|
1729
2063
|
if (hasTmux) {
|
|
1730
|
-
|
|
2064
|
+
logger3.info("Launching agents in tmux panes...");
|
|
1731
2065
|
console.log();
|
|
1732
2066
|
const sessionName = `rapid-${Date.now()}`;
|
|
1733
2067
|
const firstAgent = selectedAgents[0];
|
|
@@ -1743,29 +2077,29 @@ async function runMultiAgent(config, rootDir, options) {
|
|
|
1743
2077
|
});
|
|
1744
2078
|
await execa4("tmux", ["select-layout", "-t", sessionName, "tiled"]);
|
|
1745
2079
|
}
|
|
1746
|
-
|
|
2080
|
+
logger3.success(`Started ${selectedAgents.length} agents in tmux session: ${sessionName}`);
|
|
1747
2081
|
console.log();
|
|
1748
|
-
|
|
1749
|
-
|
|
2082
|
+
logger3.info("Attaching to tmux session...");
|
|
2083
|
+
logger3.dim("Press Ctrl+B then D to detach, or Ctrl+B then arrow keys to switch panes");
|
|
1750
2084
|
console.log();
|
|
1751
2085
|
await execa4("tmux", ["attach-session", "-t", sessionName], {
|
|
1752
2086
|
stdio: "inherit"
|
|
1753
2087
|
});
|
|
1754
2088
|
} else {
|
|
1755
|
-
|
|
2089
|
+
logger3.warn("tmux not found. Multi-agent mode works best with tmux installed.");
|
|
1756
2090
|
console.log();
|
|
1757
|
-
|
|
2091
|
+
logger3.info("To run multiple agents, open separate terminal windows and run:");
|
|
1758
2092
|
console.log();
|
|
1759
2093
|
for (const name of selectedAgents) {
|
|
1760
2094
|
const cmd = options.local ? `--local` : "";
|
|
1761
2095
|
console.log(
|
|
1762
|
-
` ${
|
|
2096
|
+
` ${logger3.dim("Terminal " + (selectedAgents.indexOf(name) + 1) + ":")} rapid dev --agent ${name} ${cmd}`.trim()
|
|
1763
2097
|
);
|
|
1764
2098
|
}
|
|
1765
2099
|
console.log();
|
|
1766
|
-
|
|
1767
|
-
console.log(` ${
|
|
1768
|
-
console.log(` ${
|
|
2100
|
+
logger3.info("Install tmux for integrated multi-pane support:");
|
|
2101
|
+
console.log(` ${logger3.dim("macOS:")} brew install tmux`);
|
|
2102
|
+
console.log(` ${logger3.dim("Ubuntu:")} sudo apt install tmux`);
|
|
1769
2103
|
console.log();
|
|
1770
2104
|
}
|
|
1771
2105
|
}
|
|
@@ -1775,7 +2109,7 @@ import { Command as Command3 } from "commander";
|
|
|
1775
2109
|
import {
|
|
1776
2110
|
loadConfig as loadConfig2,
|
|
1777
2111
|
checkAllAgents,
|
|
1778
|
-
logger as
|
|
2112
|
+
logger as logger4,
|
|
1779
2113
|
getContainerStatus as getContainerStatus2,
|
|
1780
2114
|
hasDevcontainerCli as hasDevcontainerCli2,
|
|
1781
2115
|
hasDocker,
|
|
@@ -1871,39 +2205,39 @@ var statusCommand = new Command3("status").description("Show environment status"
|
|
|
1871
2205
|
return;
|
|
1872
2206
|
}
|
|
1873
2207
|
console.log();
|
|
1874
|
-
console.log(` ${
|
|
1875
|
-
console.log(` ${
|
|
2208
|
+
console.log(` ${logger4.brand("RAPID")} Status`);
|
|
2209
|
+
console.log(` ${logger4.dim("\u2500".repeat(24))}`);
|
|
1876
2210
|
console.log();
|
|
1877
|
-
console.log(` ${
|
|
1878
|
-
console.log(` ${
|
|
2211
|
+
console.log(` ${logger4.dim("Config:")} ${filepath}`);
|
|
2212
|
+
console.log(` ${logger4.dim("Root:")} ${rootDir}`);
|
|
1879
2213
|
console.log();
|
|
1880
|
-
console.log(` ${
|
|
2214
|
+
console.log(` ${logger4.dim("Container:")}`);
|
|
1881
2215
|
if (!devcontainerConfig) {
|
|
1882
|
-
console.log(` ${
|
|
2216
|
+
console.log(` ${logger4.dim("\u25CB")} ${logger4.dim("No devcontainer.json configured")}`);
|
|
1883
2217
|
} else if (!dockerRunning) {
|
|
1884
|
-
console.log(` ${
|
|
2218
|
+
console.log(` ${logger4.dim("\u25CB")} ${logger4.dim("Docker not running")}`);
|
|
1885
2219
|
} else if (!hasDevCli) {
|
|
1886
|
-
console.log(` ${
|
|
2220
|
+
console.log(` ${logger4.dim("\u25CB")} ${logger4.dim("devcontainer CLI not installed")}`);
|
|
1887
2221
|
} else if (containerStatus.running) {
|
|
1888
2222
|
console.log(
|
|
1889
|
-
` ${
|
|
2223
|
+
` ${logger4.brand("\u25CF")} Running ${logger4.dim(`(${containerStatus.containerName})`)}`
|
|
1890
2224
|
);
|
|
1891
2225
|
} else if (containerStatus.exists) {
|
|
1892
2226
|
console.log(
|
|
1893
|
-
` ${
|
|
2227
|
+
` ${logger4.dim("\u25CB")} Stopped ${logger4.dim(`(${containerStatus.containerName})`)}`
|
|
1894
2228
|
);
|
|
1895
2229
|
} else {
|
|
1896
|
-
console.log(` ${
|
|
2230
|
+
console.log(` ${logger4.dim("\u25CB")} Not started`);
|
|
1897
2231
|
}
|
|
1898
2232
|
console.log();
|
|
1899
2233
|
console.log(
|
|
1900
|
-
` ${
|
|
2234
|
+
` ${logger4.dim("Agents:")} ${logger4.dim(`(default: ${config.agents.default})`)}`
|
|
1901
2235
|
);
|
|
1902
2236
|
agentStatuses.forEach((status) => {
|
|
1903
2237
|
const isDefault = status.name === config.agents.default;
|
|
1904
|
-
const icon = status.available ?
|
|
1905
|
-
const name = isDefault ?
|
|
1906
|
-
const version = status.version ?
|
|
2238
|
+
const icon = status.available ? logger4.brand("\u2713") : logger4.dim("\u25CB");
|
|
2239
|
+
const name = isDefault ? logger4.bold(status.name) : status.name;
|
|
2240
|
+
const version = status.version ? logger4.dim(` (${status.version})`) : "";
|
|
1907
2241
|
console.log(` ${icon} ${name}${version}`);
|
|
1908
2242
|
});
|
|
1909
2243
|
console.log();
|
|
@@ -1911,38 +2245,38 @@ var statusCommand = new Command3("status").description("Show environment status"
|
|
|
1911
2245
|
const providerInfo = getProviderInfo(
|
|
1912
2246
|
secretsStatus.provider
|
|
1913
2247
|
);
|
|
1914
|
-
console.log(` ${
|
|
2248
|
+
console.log(` ${logger4.dim("Secrets:")} ${logger4.dim(`(${providerInfo.name})`)}`);
|
|
1915
2249
|
if (providerInfo.cliRequired) {
|
|
1916
|
-
const cliIcon = secretsStatus.cliInstalled ?
|
|
2250
|
+
const cliIcon = secretsStatus.cliInstalled ? logger4.brand("\u2713") : logger4.dim("\u25CB");
|
|
1917
2251
|
console.log(
|
|
1918
2252
|
` ${cliIcon} CLI ${secretsStatus.cliInstalled ? "installed" : "not installed"}`
|
|
1919
2253
|
);
|
|
1920
2254
|
if (secretsStatus.cliInstalled) {
|
|
1921
|
-
const authIcon = secretsStatus.authenticated ?
|
|
2255
|
+
const authIcon = secretsStatus.authenticated ? logger4.brand("\u2713") : logger4.dim("\u25CB");
|
|
1922
2256
|
console.log(
|
|
1923
2257
|
` ${authIcon} ${secretsStatus.authenticated ? "Authenticated" : "Not authenticated"}`
|
|
1924
2258
|
);
|
|
1925
2259
|
}
|
|
1926
2260
|
}
|
|
1927
2261
|
if (secretsStatus.secretsCount > 0) {
|
|
1928
|
-
const allIcon = secretsStatus.allAvailable ?
|
|
2262
|
+
const allIcon = secretsStatus.allAvailable ? logger4.brand("\u2713") : logger4.dim("\u25CB");
|
|
1929
2263
|
console.log(
|
|
1930
2264
|
` ${allIcon} ${secretsStatus.secretsCount} secret${secretsStatus.secretsCount !== 1 ? "s" : ""} ${secretsStatus.allAvailable ? "available" : "configured"}`
|
|
1931
2265
|
);
|
|
1932
2266
|
}
|
|
1933
|
-
const envrcIcon = secretsStatus.envrcExists ?
|
|
2267
|
+
const envrcIcon = secretsStatus.envrcExists ? logger4.brand("\u2713") : logger4.dim("\u25CB");
|
|
1934
2268
|
console.log(
|
|
1935
2269
|
` ${envrcIcon} .envrc ${secretsStatus.envrcExists ? "exists" : "not generated"}`
|
|
1936
2270
|
);
|
|
1937
2271
|
console.log();
|
|
1938
2272
|
}
|
|
1939
|
-
console.log(` ${
|
|
2273
|
+
console.log(` ${logger4.dim("Auth:")}`);
|
|
1940
2274
|
if (!authStatus.authenticated) {
|
|
1941
|
-
console.log(` ${
|
|
1942
|
-
console.log(` ${
|
|
2275
|
+
console.log(` ${logger4.dim("\u25CB")} ${logger4.dim("No authentication detected")}`);
|
|
2276
|
+
console.log(` ${logger4.dim(" Run `rapid auth` for options")}`);
|
|
1943
2277
|
} else {
|
|
1944
2278
|
for (const cred of authStatus.sources) {
|
|
1945
|
-
const icon = cred.authType === "oauth" ?
|
|
2279
|
+
const icon = cred.authType === "oauth" ? logger4.brand("\u25CF") : logger4.dim("\u25CB");
|
|
1946
2280
|
const authType = cred.authType === "oauth" ? "OAuth" : "API Key";
|
|
1947
2281
|
let info = `${cred.source} (${cred.provider}, ${authType})`;
|
|
1948
2282
|
if (cred.accountInfo?.email) {
|
|
@@ -1953,32 +2287,32 @@ var statusCommand = new Command3("status").description("Show environment status"
|
|
|
1953
2287
|
}
|
|
1954
2288
|
console.log();
|
|
1955
2289
|
if (!containerStatus.running && devcontainerConfig && dockerRunning && hasDevCli) {
|
|
1956
|
-
|
|
2290
|
+
logger4.info("Run `rapid start` to start the container");
|
|
1957
2291
|
} else if (containerStatus.running) {
|
|
1958
|
-
|
|
2292
|
+
logger4.info("Run `rapid dev` to start coding");
|
|
1959
2293
|
}
|
|
1960
2294
|
console.log();
|
|
1961
2295
|
} catch (error) {
|
|
1962
|
-
|
|
2296
|
+
logger4.error(error instanceof Error ? error.message : String(error));
|
|
1963
2297
|
process.exit(1);
|
|
1964
2298
|
}
|
|
1965
2299
|
});
|
|
1966
2300
|
|
|
1967
2301
|
// src/commands/agent.ts
|
|
1968
|
-
import { writeFile as
|
|
2302
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
1969
2303
|
import { Command as Command4 } from "commander";
|
|
1970
|
-
import { loadConfig as loadConfig3, checkAllAgents as checkAllAgents2, logger as
|
|
2304
|
+
import { loadConfig as loadConfig3, checkAllAgents as checkAllAgents2, logger as logger5, formatJson as formatJson4 } from "@a3t/rapid-core";
|
|
1971
2305
|
var agentCommand = new Command4("agent").description("Manage AI agents");
|
|
1972
2306
|
agentCommand.command("list").description("List available agents").action(async () => {
|
|
1973
2307
|
try {
|
|
1974
2308
|
const loaded = await loadConfig3();
|
|
1975
2309
|
if (!loaded) {
|
|
1976
|
-
|
|
2310
|
+
logger5.error("No rapid.json found. Run `rapid init` first.");
|
|
1977
2311
|
process.exit(1);
|
|
1978
2312
|
}
|
|
1979
2313
|
const { config } = loaded;
|
|
1980
2314
|
const statuses = await checkAllAgents2(config);
|
|
1981
|
-
|
|
2315
|
+
logger5.header("Available Agents");
|
|
1982
2316
|
statuses.forEach((status) => {
|
|
1983
2317
|
const isDefault = status.name === config.agents.default;
|
|
1984
2318
|
const icon = status.available ? "\u2713" : "\u25CB";
|
|
@@ -1986,17 +2320,17 @@ agentCommand.command("list").description("List available agents").action(async (
|
|
|
1986
2320
|
const versionTag = status.version ? ` - ${status.version}` : "";
|
|
1987
2321
|
if (status.available) {
|
|
1988
2322
|
console.log(
|
|
1989
|
-
` ${
|
|
2323
|
+
` ${logger5.brand(icon)} ${status.name}${defaultTag}${logger5.dim(versionTag)}`
|
|
1990
2324
|
);
|
|
1991
2325
|
} else {
|
|
1992
2326
|
console.log(
|
|
1993
|
-
` ${
|
|
2327
|
+
` ${logger5.dim(icon)} ${logger5.dim(status.name)}${defaultTag} ${logger5.dim("[not installed]")}`
|
|
1994
2328
|
);
|
|
1995
2329
|
}
|
|
1996
2330
|
});
|
|
1997
|
-
|
|
2331
|
+
logger5.blank();
|
|
1998
2332
|
} catch (error) {
|
|
1999
|
-
|
|
2333
|
+
logger5.error(error instanceof Error ? error.message : String(error));
|
|
2000
2334
|
process.exit(1);
|
|
2001
2335
|
}
|
|
2002
2336
|
});
|
|
@@ -2004,7 +2338,7 @@ agentCommand.command("default [name]").description("Get or set default agent").a
|
|
|
2004
2338
|
try {
|
|
2005
2339
|
const loaded = await loadConfig3();
|
|
2006
2340
|
if (!loaded) {
|
|
2007
|
-
|
|
2341
|
+
logger5.error("No rapid.json found. Run `rapid init` first.");
|
|
2008
2342
|
process.exit(1);
|
|
2009
2343
|
}
|
|
2010
2344
|
const { config } = loaded;
|
|
@@ -2013,18 +2347,18 @@ agentCommand.command("default [name]").description("Get or set default agent").a
|
|
|
2013
2347
|
return;
|
|
2014
2348
|
}
|
|
2015
2349
|
if (!config.agents.available[name]) {
|
|
2016
|
-
|
|
2017
|
-
|
|
2350
|
+
logger5.error(`Agent "${name}" not found in configuration`);
|
|
2351
|
+
logger5.info("Available agents:");
|
|
2018
2352
|
Object.keys(config.agents.available).forEach((n) => {
|
|
2019
2353
|
console.log(` - ${n}`);
|
|
2020
2354
|
});
|
|
2021
2355
|
process.exit(1);
|
|
2022
2356
|
}
|
|
2023
2357
|
config.agents.default = name;
|
|
2024
|
-
await
|
|
2025
|
-
|
|
2358
|
+
await writeFile5(loaded.filepath, await formatJson4(config));
|
|
2359
|
+
logger5.success(`Default agent set to "${name}"`);
|
|
2026
2360
|
} catch (error) {
|
|
2027
|
-
|
|
2361
|
+
logger5.error(error instanceof Error ? error.message : String(error));
|
|
2028
2362
|
process.exit(1);
|
|
2029
2363
|
}
|
|
2030
2364
|
});
|
|
@@ -2032,14 +2366,14 @@ agentCommand.command("yolo [name]").description("Enable YOLO mode (skip all perm
|
|
|
2032
2366
|
try {
|
|
2033
2367
|
const loaded = await loadConfig3();
|
|
2034
2368
|
if (!loaded) {
|
|
2035
|
-
|
|
2369
|
+
logger5.error("No rapid.json found. Run `rapid init` first.");
|
|
2036
2370
|
process.exit(1);
|
|
2037
2371
|
}
|
|
2038
2372
|
const { config } = loaded;
|
|
2039
2373
|
const agentName = name || config.agents.default;
|
|
2040
2374
|
if (!config.agents.available[agentName]) {
|
|
2041
|
-
|
|
2042
|
-
|
|
2375
|
+
logger5.error(`Agent "${agentName}" not found in configuration`);
|
|
2376
|
+
logger5.info("Available agents:");
|
|
2043
2377
|
Object.keys(config.agents.available).forEach((n) => {
|
|
2044
2378
|
console.log(` - ${n}`);
|
|
2045
2379
|
});
|
|
@@ -2048,19 +2382,19 @@ agentCommand.command("yolo [name]").description("Enable YOLO mode (skip all perm
|
|
|
2048
2382
|
const agent = config.agents.available[agentName];
|
|
2049
2383
|
const enabling = !options.off;
|
|
2050
2384
|
if (enabling && agent.cli !== "claude") {
|
|
2051
|
-
|
|
2052
|
-
|
|
2385
|
+
logger5.warn(`YOLO mode is only supported for Claude (${agentName} uses ${agent.cli})`);
|
|
2386
|
+
logger5.info("Continuing anyway...");
|
|
2053
2387
|
}
|
|
2054
2388
|
agent.yolo = enabling;
|
|
2055
|
-
await
|
|
2389
|
+
await writeFile5(loaded.filepath, await formatJson4(config));
|
|
2056
2390
|
if (enabling) {
|
|
2057
|
-
|
|
2058
|
-
|
|
2391
|
+
logger5.success(`YOLO mode enabled for "${agentName}"`);
|
|
2392
|
+
logger5.dim("Permission prompts will be skipped (--dangerously-skip-permissions)");
|
|
2059
2393
|
} else {
|
|
2060
|
-
|
|
2394
|
+
logger5.success(`YOLO mode disabled for "${agentName}"`);
|
|
2061
2395
|
}
|
|
2062
2396
|
} catch (error) {
|
|
2063
|
-
|
|
2397
|
+
logger5.error(error instanceof Error ? error.message : String(error));
|
|
2064
2398
|
process.exit(1);
|
|
2065
2399
|
}
|
|
2066
2400
|
});
|
|
@@ -2069,7 +2403,7 @@ agentCommand.command("yolo [name]").description("Enable YOLO mode (skip all perm
|
|
|
2069
2403
|
import { Command as Command5 } from "commander";
|
|
2070
2404
|
import {
|
|
2071
2405
|
loadConfig as loadConfig4,
|
|
2072
|
-
logger as
|
|
2406
|
+
logger as logger6,
|
|
2073
2407
|
hasDevcontainerCli as hasDevcontainerCli3,
|
|
2074
2408
|
hasDocker as hasDocker2,
|
|
2075
2409
|
loadDevcontainerConfig as loadDevcontainerConfig2,
|
|
@@ -2091,36 +2425,36 @@ var startCommand = new Command5("start").description("Start the development cont
|
|
|
2091
2425
|
const hasDevCli = await hasDevcontainerCli3();
|
|
2092
2426
|
if (!hasDevCli) {
|
|
2093
2427
|
spinner.fail("devcontainer CLI not found");
|
|
2094
|
-
|
|
2095
|
-
|
|
2428
|
+
logger6.blank();
|
|
2429
|
+
logger6.info("Install with:");
|
|
2096
2430
|
console.log(" npm install -g @devcontainers/cli");
|
|
2097
|
-
|
|
2431
|
+
logger6.blank();
|
|
2098
2432
|
process.exit(1);
|
|
2099
2433
|
}
|
|
2100
2434
|
spinner.text = "Checking Docker...";
|
|
2101
2435
|
const dockerAvailable = await hasDocker2();
|
|
2102
2436
|
if (!dockerAvailable) {
|
|
2103
2437
|
spinner.fail("Docker is not running");
|
|
2104
|
-
|
|
2438
|
+
logger6.info("Please start Docker Desktop and try again.");
|
|
2105
2439
|
process.exit(1);
|
|
2106
2440
|
}
|
|
2107
2441
|
spinner.text = "Checking devcontainer configuration...";
|
|
2108
2442
|
const devcontainerConfig = await loadDevcontainerConfig2(rootDir, config);
|
|
2109
2443
|
if (!devcontainerConfig) {
|
|
2110
2444
|
spinner.fail("No devcontainer.json found");
|
|
2111
|
-
|
|
2112
|
-
|
|
2445
|
+
logger6.blank();
|
|
2446
|
+
logger6.info("Create a .devcontainer/devcontainer.json or run:");
|
|
2113
2447
|
console.log(" rapid init --template <template>");
|
|
2114
|
-
|
|
2448
|
+
logger6.blank();
|
|
2115
2449
|
process.exit(1);
|
|
2116
2450
|
}
|
|
2117
2451
|
spinner.text = "Checking container status...";
|
|
2118
2452
|
const status = await getContainerStatus3(rootDir, config);
|
|
2119
2453
|
if (status.running && !options.rebuild) {
|
|
2120
2454
|
spinner.succeed("Container already running");
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2455
|
+
logger6.info(`Container: ${status.containerName}`);
|
|
2456
|
+
logger6.blank();
|
|
2457
|
+
logger6.info("Run `rapid dev` to start coding");
|
|
2124
2458
|
return;
|
|
2125
2459
|
}
|
|
2126
2460
|
spinner.text = options.rebuild ? "Rebuilding container..." : "Starting container...";
|
|
@@ -2130,28 +2464,28 @@ var startCommand = new Command5("start").description("Start the development cont
|
|
|
2130
2464
|
quiet: false
|
|
2131
2465
|
});
|
|
2132
2466
|
if (!result.success) {
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2467
|
+
logger6.blank();
|
|
2468
|
+
logger6.error("Failed to start container");
|
|
2469
|
+
logger6.error(result.error || "Unknown error");
|
|
2136
2470
|
process.exit(1);
|
|
2137
2471
|
}
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
console.log(` ${
|
|
2143
|
-
console.log(` ${
|
|
2144
|
-
|
|
2472
|
+
logger6.blank();
|
|
2473
|
+
logger6.success("Development environment ready!");
|
|
2474
|
+
logger6.blank();
|
|
2475
|
+
logger6.info("Next steps:");
|
|
2476
|
+
console.log(` ${logger6.dim("\u2022")} Run ${logger6.brand("rapid dev")} to start coding`);
|
|
2477
|
+
console.log(` ${logger6.dim("\u2022")} Run ${logger6.brand("rapid stop")} when done`);
|
|
2478
|
+
logger6.blank();
|
|
2145
2479
|
} catch (error) {
|
|
2146
2480
|
spinner.fail("Failed to start environment");
|
|
2147
|
-
|
|
2481
|
+
logger6.error(error instanceof Error ? error.message : String(error));
|
|
2148
2482
|
process.exit(1);
|
|
2149
2483
|
}
|
|
2150
2484
|
});
|
|
2151
2485
|
|
|
2152
2486
|
// src/commands/stop.ts
|
|
2153
2487
|
import { Command as Command6 } from "commander";
|
|
2154
|
-
import { loadConfig as loadConfig5, logger as
|
|
2488
|
+
import { loadConfig as loadConfig5, logger as logger7, getContainerStatus as getContainerStatus4, stopContainer } from "@a3t/rapid-core";
|
|
2155
2489
|
import ora5 from "ora";
|
|
2156
2490
|
var stopCommand = new Command6("stop").description("Stop the development container").option("--remove", "Remove container after stopping", false).action(async (options) => {
|
|
2157
2491
|
const spinner = ora5("Stopping development environment...").start();
|
|
@@ -2182,13 +2516,13 @@ var stopCommand = new Command6("stop").description("Stop the development contain
|
|
|
2182
2516
|
const result = await stopContainer(rootDir, config, { remove: options.remove });
|
|
2183
2517
|
if (!result.success) {
|
|
2184
2518
|
spinner.fail("Failed to stop container");
|
|
2185
|
-
|
|
2519
|
+
logger7.error(result.error || "Unknown error");
|
|
2186
2520
|
process.exit(1);
|
|
2187
2521
|
}
|
|
2188
2522
|
spinner.succeed(options.remove ? "Container stopped and removed" : "Container stopped");
|
|
2189
2523
|
} catch (error) {
|
|
2190
2524
|
spinner.fail("Failed to stop environment");
|
|
2191
|
-
|
|
2525
|
+
logger7.error(error instanceof Error ? error.message : String(error));
|
|
2192
2526
|
process.exit(1);
|
|
2193
2527
|
}
|
|
2194
2528
|
});
|
|
@@ -2197,7 +2531,7 @@ var stopCommand = new Command6("stop").description("Stop the development contain
|
|
|
2197
2531
|
import { Command as Command7 } from "commander";
|
|
2198
2532
|
import {
|
|
2199
2533
|
loadConfig as loadConfig6,
|
|
2200
|
-
logger as
|
|
2534
|
+
logger as logger8,
|
|
2201
2535
|
verifySecrets as verifySecrets2,
|
|
2202
2536
|
loadSecrets as loadSecrets2,
|
|
2203
2537
|
hasOpCli as hasOpCli3,
|
|
@@ -2234,15 +2568,15 @@ secretsCommand.command("verify").description("Verify all secrets are accessible"
|
|
|
2234
2568
|
if (!hasOp) {
|
|
2235
2569
|
spinner.fail("1Password CLI (op) not found");
|
|
2236
2570
|
console.log();
|
|
2237
|
-
|
|
2238
|
-
|
|
2571
|
+
logger8.info("Install with: brew install 1password-cli");
|
|
2572
|
+
logger8.info("More info: https://developer.1password.com/docs/cli/get-started/");
|
|
2239
2573
|
process.exit(1);
|
|
2240
2574
|
}
|
|
2241
2575
|
const authenticated = await isOpAuthenticated3();
|
|
2242
2576
|
if (!authenticated) {
|
|
2243
2577
|
spinner.fail("1Password CLI not authenticated");
|
|
2244
2578
|
console.log();
|
|
2245
|
-
|
|
2579
|
+
logger8.info("Run: eval $(op signin)");
|
|
2246
2580
|
process.exit(1);
|
|
2247
2581
|
}
|
|
2248
2582
|
} else if (provider === "vault") {
|
|
@@ -2250,14 +2584,14 @@ secretsCommand.command("verify").description("Verify all secrets are accessible"
|
|
|
2250
2584
|
if (!hasVault) {
|
|
2251
2585
|
spinner.fail("Vault CLI not found");
|
|
2252
2586
|
console.log();
|
|
2253
|
-
|
|
2587
|
+
logger8.info("Install from: https://developer.hashicorp.com/vault/docs/install");
|
|
2254
2588
|
process.exit(1);
|
|
2255
2589
|
}
|
|
2256
2590
|
const authenticated = await isVaultAuthenticated3();
|
|
2257
2591
|
if (!authenticated) {
|
|
2258
2592
|
spinner.fail("Vault CLI not authenticated");
|
|
2259
2593
|
console.log();
|
|
2260
|
-
|
|
2594
|
+
logger8.info("Run: vault login");
|
|
2261
2595
|
process.exit(1);
|
|
2262
2596
|
}
|
|
2263
2597
|
}
|
|
@@ -2269,37 +2603,37 @@ secretsCommand.command("verify").description("Verify all secrets are accessible"
|
|
|
2269
2603
|
return;
|
|
2270
2604
|
}
|
|
2271
2605
|
console.log();
|
|
2272
|
-
console.log(` ${
|
|
2273
|
-
console.log(` ${
|
|
2606
|
+
console.log(` ${logger8.brand("Secrets")} Verification`);
|
|
2607
|
+
console.log(` ${logger8.dim("\u2500".repeat(24))}`);
|
|
2274
2608
|
console.log();
|
|
2275
|
-
console.log(` ${
|
|
2609
|
+
console.log(` ${logger8.dim("Provider:")} ${getProviderInfo2(provider).name}`);
|
|
2276
2610
|
console.log(
|
|
2277
|
-
` ${
|
|
2611
|
+
` ${logger8.dim("Auth:")} ${status.authenticated ? logger8.brand("\u2713") : logger8.dim("\u25CB")} ${status.authenticated ? "Authenticated" : "Not authenticated"}`
|
|
2278
2612
|
);
|
|
2279
2613
|
console.log();
|
|
2280
2614
|
if (status.secrets.length === 0) {
|
|
2281
|
-
console.log(` ${
|
|
2615
|
+
console.log(` ${logger8.dim("No secrets configured in rapid.json")}`);
|
|
2282
2616
|
console.log();
|
|
2283
2617
|
return;
|
|
2284
2618
|
}
|
|
2285
|
-
console.log(` ${
|
|
2619
|
+
console.log(` ${logger8.dim("Secrets:")}`);
|
|
2286
2620
|
for (const secret of status.secrets) {
|
|
2287
|
-
const icon = secret.available ?
|
|
2288
|
-
const ref =
|
|
2289
|
-
const error = secret.error ?
|
|
2621
|
+
const icon = secret.available ? logger8.brand("\u2713") : "\u2717";
|
|
2622
|
+
const ref = logger8.dim(`(${provider})`);
|
|
2623
|
+
const error = secret.error ? logger8.dim(` - ${secret.error}`) : "";
|
|
2290
2624
|
console.log(` ${icon} ${secret.name} ${ref}${error}`);
|
|
2291
2625
|
}
|
|
2292
2626
|
console.log();
|
|
2293
2627
|
if (status.allAvailable) {
|
|
2294
|
-
|
|
2628
|
+
logger8.info("All secrets verified successfully!");
|
|
2295
2629
|
} else {
|
|
2296
|
-
|
|
2630
|
+
logger8.error("Some secrets are not available");
|
|
2297
2631
|
process.exit(1);
|
|
2298
2632
|
}
|
|
2299
2633
|
console.log();
|
|
2300
2634
|
} catch (error) {
|
|
2301
2635
|
spinner.fail("Failed to verify secrets");
|
|
2302
|
-
|
|
2636
|
+
logger8.error(error instanceof Error ? error.message : String(error));
|
|
2303
2637
|
process.exit(1);
|
|
2304
2638
|
}
|
|
2305
2639
|
});
|
|
@@ -2307,7 +2641,7 @@ secretsCommand.command("list").description("List configured secrets (names only,
|
|
|
2307
2641
|
try {
|
|
2308
2642
|
const loaded = await loadConfig6();
|
|
2309
2643
|
if (!loaded) {
|
|
2310
|
-
|
|
2644
|
+
logger8.error("No rapid.json found");
|
|
2311
2645
|
process.exit(1);
|
|
2312
2646
|
}
|
|
2313
2647
|
const { config } = loaded;
|
|
@@ -2316,7 +2650,7 @@ secretsCommand.command("list").description("List configured secrets (names only,
|
|
|
2316
2650
|
if (options.json) {
|
|
2317
2651
|
console.log(JSON.stringify({ secrets: [] }, null, 2));
|
|
2318
2652
|
} else {
|
|
2319
|
-
|
|
2653
|
+
logger8.info("No secrets configured");
|
|
2320
2654
|
}
|
|
2321
2655
|
return;
|
|
2322
2656
|
}
|
|
@@ -2331,19 +2665,19 @@ secretsCommand.command("list").description("List configured secrets (names only,
|
|
|
2331
2665
|
return;
|
|
2332
2666
|
}
|
|
2333
2667
|
console.log();
|
|
2334
|
-
console.log(` ${
|
|
2335
|
-
console.log(` ${
|
|
2668
|
+
console.log(` ${logger8.brand("Configured Secrets")}`);
|
|
2669
|
+
console.log(` ${logger8.dim("\u2500".repeat(24))}`);
|
|
2336
2670
|
console.log();
|
|
2337
|
-
console.log(` ${
|
|
2671
|
+
console.log(` ${logger8.dim("Provider:")} ${getProviderInfo2(provider).name}`);
|
|
2338
2672
|
console.log();
|
|
2339
2673
|
const maxNameLen = Math.max(...Object.keys(secretsConfig.items).map((n) => n.length));
|
|
2340
2674
|
for (const [name, reference] of Object.entries(secretsConfig.items)) {
|
|
2341
2675
|
const paddedName = name.padEnd(maxNameLen);
|
|
2342
|
-
console.log(` ${
|
|
2676
|
+
console.log(` ${logger8.brand("\u2022")} ${paddedName} ${logger8.dim(reference)}`);
|
|
2343
2677
|
}
|
|
2344
2678
|
console.log();
|
|
2345
2679
|
} catch (error) {
|
|
2346
|
-
|
|
2680
|
+
logger8.error(error instanceof Error ? error.message : String(error));
|
|
2347
2681
|
process.exit(1);
|
|
2348
2682
|
}
|
|
2349
2683
|
});
|
|
@@ -2351,13 +2685,13 @@ secretsCommand.command("generate").description("Generate .envrc file from rapid.
|
|
|
2351
2685
|
try {
|
|
2352
2686
|
const loaded = await loadConfig6();
|
|
2353
2687
|
if (!loaded) {
|
|
2354
|
-
|
|
2688
|
+
logger8.error("No rapid.json found");
|
|
2355
2689
|
process.exit(1);
|
|
2356
2690
|
}
|
|
2357
2691
|
const { config, rootDir } = loaded;
|
|
2358
2692
|
const secretsConfig = config.secrets;
|
|
2359
2693
|
if (!secretsConfig) {
|
|
2360
|
-
|
|
2694
|
+
logger8.error("No secrets configuration in rapid.json");
|
|
2361
2695
|
process.exit(1);
|
|
2362
2696
|
}
|
|
2363
2697
|
const content = generateEnvrc(secretsConfig);
|
|
@@ -2367,21 +2701,21 @@ secretsCommand.command("generate").description("Generate .envrc file from rapid.
|
|
|
2367
2701
|
}
|
|
2368
2702
|
const envrcExists = await hasEnvrc2(rootDir, secretsConfig);
|
|
2369
2703
|
if (envrcExists && !options.force) {
|
|
2370
|
-
|
|
2704
|
+
logger8.error(".envrc already exists. Use --force to overwrite.");
|
|
2371
2705
|
process.exit(1);
|
|
2372
2706
|
}
|
|
2373
2707
|
const spinner = ora6("Generating .envrc...").start();
|
|
2374
2708
|
const filepath = await writeEnvrc(rootDir, secretsConfig);
|
|
2375
2709
|
spinner.succeed("Generated .envrc");
|
|
2376
2710
|
console.log();
|
|
2377
|
-
console.log(` ${
|
|
2711
|
+
console.log(` ${logger8.dim("File:")} ${filepath}`);
|
|
2378
2712
|
console.log();
|
|
2379
2713
|
const itemCount = secretsConfig.items ? Object.keys(secretsConfig.items).length : 0;
|
|
2380
|
-
|
|
2381
|
-
|
|
2714
|
+
logger8.info(`Generated .envrc with ${itemCount} secret${itemCount !== 1 ? "s" : ""}`);
|
|
2715
|
+
logger8.info(`Run ${logger8.brand("direnv allow")} to activate`);
|
|
2382
2716
|
console.log();
|
|
2383
2717
|
} catch (error) {
|
|
2384
|
-
|
|
2718
|
+
logger8.error(error instanceof Error ? error.message : String(error));
|
|
2385
2719
|
process.exit(1);
|
|
2386
2720
|
}
|
|
2387
2721
|
});
|
|
@@ -2433,59 +2767,59 @@ secretsCommand.command("info").description("Show secrets provider information an
|
|
|
2433
2767
|
return;
|
|
2434
2768
|
}
|
|
2435
2769
|
console.log();
|
|
2436
|
-
console.log(` ${
|
|
2437
|
-
console.log(` ${
|
|
2770
|
+
console.log(` ${logger8.brand("Secrets")} Provider Info`);
|
|
2771
|
+
console.log(` ${logger8.dim("\u2500".repeat(24))}`);
|
|
2438
2772
|
console.log();
|
|
2439
|
-
console.log(` ${
|
|
2773
|
+
console.log(` ${logger8.dim("Provider:")} ${info.name}`);
|
|
2440
2774
|
if (info.cliRequired) {
|
|
2441
|
-
const cliIcon = cliInstalled ?
|
|
2775
|
+
const cliIcon = cliInstalled ? logger8.brand("\u2713") : "\u2717";
|
|
2442
2776
|
console.log(
|
|
2443
|
-
` ${
|
|
2777
|
+
` ${logger8.dim("CLI:")} ${cliIcon} ${info.cliRequired} ${cliInstalled ? "" : logger8.dim("(not installed)")}`
|
|
2444
2778
|
);
|
|
2445
2779
|
if (cliInstalled && provider === "1password" && opAuthStatus) {
|
|
2446
|
-
const authIcon = authenticated ?
|
|
2780
|
+
const authIcon = authenticated ? logger8.brand("\u2713") : "\u2717";
|
|
2447
2781
|
const methodLabel = opAuthStatus.method === "service-account" ? "Service Account" : opAuthStatus.method === "user" ? "User" : "Not authenticated";
|
|
2448
2782
|
const accountLabel = opAuthStatus.accountInfo ? ` (${opAuthStatus.accountInfo})` : "";
|
|
2449
|
-
console.log(` ${
|
|
2783
|
+
console.log(` ${logger8.dim("Auth:")} ${authIcon} ${methodLabel}${accountLabel}`);
|
|
2450
2784
|
if (hasServiceToken) {
|
|
2451
2785
|
console.log(
|
|
2452
|
-
` ${
|
|
2786
|
+
` ${logger8.dim("Token:")} ${logger8.brand("\u2713")} OP_SERVICE_ACCOUNT_TOKEN set`
|
|
2453
2787
|
);
|
|
2454
2788
|
}
|
|
2455
2789
|
} else if (cliInstalled) {
|
|
2456
|
-
const authIcon = authenticated ?
|
|
2790
|
+
const authIcon = authenticated ? logger8.brand("\u2713") : "\u2717";
|
|
2457
2791
|
console.log(
|
|
2458
|
-
` ${
|
|
2792
|
+
` ${logger8.dim("Auth:")} ${authIcon} ${authenticated ? "Authenticated" : "Not authenticated"}`
|
|
2459
2793
|
);
|
|
2460
2794
|
}
|
|
2461
2795
|
if (info.installUrl && !cliInstalled) {
|
|
2462
2796
|
console.log();
|
|
2463
|
-
console.log(` ${
|
|
2797
|
+
console.log(` ${logger8.dim("Install:")} ${info.installUrl}`);
|
|
2464
2798
|
}
|
|
2465
2799
|
if (info.authCommand && cliInstalled && !authenticated) {
|
|
2466
2800
|
console.log();
|
|
2467
|
-
console.log(` ${
|
|
2801
|
+
console.log(` ${logger8.dim("Authenticate:")} ${info.authCommand}`);
|
|
2468
2802
|
if (provider === "1password") {
|
|
2469
2803
|
console.log(
|
|
2470
|
-
` ${
|
|
2804
|
+
` ${logger8.dim("Or set:")} OP_SERVICE_ACCOUNT_TOKEN for non-interactive auth`
|
|
2471
2805
|
);
|
|
2472
2806
|
}
|
|
2473
2807
|
}
|
|
2474
2808
|
}
|
|
2475
2809
|
console.log();
|
|
2476
|
-
const envrcIcon = envrcExists ?
|
|
2810
|
+
const envrcIcon = envrcExists ? logger8.brand("\u2713") : logger8.dim("\u25CB");
|
|
2477
2811
|
console.log(
|
|
2478
|
-
` ${
|
|
2812
|
+
` ${logger8.dim(".envrc:")} ${envrcIcon} ${envrcExists ? "Exists" : "Not generated"}`
|
|
2479
2813
|
);
|
|
2480
|
-
console.log(` ${
|
|
2814
|
+
console.log(` ${logger8.dim("Secrets:")} ${status.secretsCount} configured`);
|
|
2481
2815
|
console.log();
|
|
2482
2816
|
if (!envrcExists && status.secretsCount > 0) {
|
|
2483
|
-
|
|
2817
|
+
logger8.info(`Run ${logger8.brand("rapid secrets generate")} to create .envrc`);
|
|
2484
2818
|
console.log();
|
|
2485
2819
|
}
|
|
2486
2820
|
} catch (error) {
|
|
2487
2821
|
spinner.fail("Failed to get provider info");
|
|
2488
|
-
|
|
2822
|
+
logger8.error(error instanceof Error ? error.message : String(error));
|
|
2489
2823
|
process.exit(1);
|
|
2490
2824
|
}
|
|
2491
2825
|
});
|
|
@@ -2493,45 +2827,45 @@ secretsCommand.command("run").description("Run a command with secrets loaded int
|
|
|
2493
2827
|
try {
|
|
2494
2828
|
const loaded = await loadConfig6();
|
|
2495
2829
|
if (!loaded) {
|
|
2496
|
-
|
|
2830
|
+
logger8.error("No rapid.json found");
|
|
2497
2831
|
process.exit(1);
|
|
2498
2832
|
}
|
|
2499
2833
|
const { config } = loaded;
|
|
2500
2834
|
const secretsConfig = config.secrets;
|
|
2501
2835
|
if (!secretsConfig || !secretsConfig.items) {
|
|
2502
|
-
|
|
2836
|
+
logger8.error("No secrets configured in rapid.json");
|
|
2503
2837
|
process.exit(1);
|
|
2504
2838
|
}
|
|
2505
2839
|
const provider = secretsConfig.provider || "env";
|
|
2506
2840
|
if (provider === "1password") {
|
|
2507
2841
|
const hasOp = await hasOpCli3();
|
|
2508
2842
|
if (!hasOp) {
|
|
2509
|
-
|
|
2510
|
-
|
|
2843
|
+
logger8.error("1Password CLI (op) not found");
|
|
2844
|
+
logger8.info("Install with: brew install 1password-cli");
|
|
2511
2845
|
process.exit(1);
|
|
2512
2846
|
}
|
|
2513
2847
|
const authenticated = await isOpAuthenticated3();
|
|
2514
2848
|
if (!authenticated) {
|
|
2515
|
-
|
|
2516
|
-
|
|
2849
|
+
logger8.error("1Password not authenticated");
|
|
2850
|
+
logger8.info("Run: eval $(op signin)");
|
|
2517
2851
|
process.exit(1);
|
|
2518
2852
|
}
|
|
2519
2853
|
}
|
|
2520
2854
|
const secrets = await loadSecrets2(secretsConfig);
|
|
2521
2855
|
const secretCount = Object.keys(secrets).length;
|
|
2522
2856
|
if (secretCount === 0) {
|
|
2523
|
-
|
|
2857
|
+
logger8.warn("No secrets were loaded");
|
|
2524
2858
|
} else if (options.show) {
|
|
2525
|
-
|
|
2859
|
+
logger8.info(`Loaded ${secretCount} secret${secretCount !== 1 ? "s" : ""}:`);
|
|
2526
2860
|
for (const name of Object.keys(secrets)) {
|
|
2527
|
-
console.log(` ${
|
|
2861
|
+
console.log(` ${logger8.brand("\u2022")} ${name}`);
|
|
2528
2862
|
}
|
|
2529
2863
|
console.log();
|
|
2530
2864
|
}
|
|
2531
2865
|
const { execa: execa4 } = await import("execa");
|
|
2532
2866
|
const [cmd, ...args] = commandArgs;
|
|
2533
2867
|
if (!cmd) {
|
|
2534
|
-
|
|
2868
|
+
logger8.error("No command specified");
|
|
2535
2869
|
process.exit(1);
|
|
2536
2870
|
}
|
|
2537
2871
|
await execa4(cmd, args, {
|
|
@@ -2545,7 +2879,7 @@ secretsCommand.command("run").description("Run a command with secrets loaded int
|
|
|
2545
2879
|
if (error.exitCode !== void 0) {
|
|
2546
2880
|
process.exit(error.exitCode);
|
|
2547
2881
|
}
|
|
2548
|
-
|
|
2882
|
+
logger8.error(error instanceof Error ? error.message : String(error));
|
|
2549
2883
|
process.exit(1);
|
|
2550
2884
|
}
|
|
2551
2885
|
});
|
|
@@ -2553,7 +2887,7 @@ secretsCommand.command("run").description("Run a command with secrets loaded int
|
|
|
2553
2887
|
// src/commands/auth.ts
|
|
2554
2888
|
import { Command as Command8 } from "commander";
|
|
2555
2889
|
import {
|
|
2556
|
-
logger as
|
|
2890
|
+
logger as logger9,
|
|
2557
2891
|
getAuthStatus as getAuthStatus2,
|
|
2558
2892
|
detectAllCredentials
|
|
2559
2893
|
} from "@a3t/rapid-core";
|
|
@@ -2597,24 +2931,24 @@ var authCommand = new Command8("auth").description("Show authentication status f
|
|
|
2597
2931
|
return;
|
|
2598
2932
|
}
|
|
2599
2933
|
console.log();
|
|
2600
|
-
console.log(` ${
|
|
2601
|
-
console.log(` ${
|
|
2934
|
+
console.log(` ${logger9.brand("RAPID")} Authentication`);
|
|
2935
|
+
console.log(` ${logger9.dim("\u2500".repeat(24))}`);
|
|
2602
2936
|
console.log();
|
|
2603
2937
|
if (!status.authenticated) {
|
|
2604
|
-
console.log(` ${
|
|
2938
|
+
console.log(` ${logger9.dim("No authentication detected")}`);
|
|
2605
2939
|
console.log();
|
|
2606
2940
|
console.log(" To authenticate, use one of these methods:");
|
|
2607
2941
|
console.log();
|
|
2608
|
-
console.log(` ${
|
|
2942
|
+
console.log(` ${logger9.brand("Claude Pro/Max:")}`);
|
|
2609
2943
|
console.log(" Run `claude` and sign in with your Anthropic account");
|
|
2610
2944
|
console.log();
|
|
2611
|
-
console.log(` ${
|
|
2945
|
+
console.log(` ${logger9.brand("OpenAI (ChatGPT Plus/Pro):")}`);
|
|
2612
2946
|
console.log(" Run `codex` and sign in with ChatGPT");
|
|
2613
2947
|
console.log();
|
|
2614
|
-
console.log(` ${
|
|
2948
|
+
console.log(` ${logger9.brand("Gemini:")}`);
|
|
2615
2949
|
console.log(" Run `gemini` and sign in with your Google account");
|
|
2616
2950
|
console.log();
|
|
2617
|
-
console.log(` ${
|
|
2951
|
+
console.log(` ${logger9.brand("API Keys:")}`);
|
|
2618
2952
|
console.log(" Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY");
|
|
2619
2953
|
console.log();
|
|
2620
2954
|
return;
|
|
@@ -2623,9 +2957,9 @@ var authCommand = new Command8("auth").description("Show authentication status f
|
|
|
2623
2957
|
if (options.source && cred.source !== options.source) continue;
|
|
2624
2958
|
if (options.provider && cred.provider !== options.provider) continue;
|
|
2625
2959
|
const isPrimary = cred === status.preferredSource;
|
|
2626
|
-
const icon = isPrimary ?
|
|
2627
|
-
const authIcon = cred.authType === "oauth" ?
|
|
2628
|
-
console.log(` ${icon} ${
|
|
2960
|
+
const icon = isPrimary ? logger9.brand("\u25CF") : logger9.dim("\u25CB");
|
|
2961
|
+
const authIcon = cred.authType === "oauth" ? logger9.brand("OAuth") : logger9.dim("API Key");
|
|
2962
|
+
console.log(` ${icon} ${logger9.bold(cred.source)}`);
|
|
2629
2963
|
console.log(` Provider: ${cred.provider}`);
|
|
2630
2964
|
console.log(` Auth: ${authIcon}`);
|
|
2631
2965
|
if (cred.accountInfo?.email) {
|
|
@@ -2635,7 +2969,7 @@ var authCommand = new Command8("auth").description("Show authentication status f
|
|
|
2635
2969
|
console.log(` Org: ${cred.accountInfo.organization}`);
|
|
2636
2970
|
}
|
|
2637
2971
|
if (cred.accountInfo?.plan) {
|
|
2638
|
-
console.log(` Plan: ${
|
|
2972
|
+
console.log(` Plan: ${logger9.brand(cred.accountInfo.plan)}`);
|
|
2639
2973
|
}
|
|
2640
2974
|
if (cred.expiresAt) {
|
|
2641
2975
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2643,32 +2977,32 @@ var authCommand = new Command8("auth").description("Show authentication status f
|
|
|
2643
2977
|
if (expiresIn > 0) {
|
|
2644
2978
|
console.log(` Expires: in ${expiresIn} minutes`);
|
|
2645
2979
|
} else {
|
|
2646
|
-
console.log(` Expires: ${
|
|
2980
|
+
console.log(` Expires: ${logger9.dim("EXPIRED")}`);
|
|
2647
2981
|
}
|
|
2648
2982
|
}
|
|
2649
2983
|
if (cred.configPath) {
|
|
2650
|
-
console.log(` Config: ${
|
|
2984
|
+
console.log(` Config: ${logger9.dim(cred.configPath)}`);
|
|
2651
2985
|
}
|
|
2652
2986
|
if (cred.envVar) {
|
|
2653
|
-
console.log(` Env: ${
|
|
2987
|
+
console.log(` Env: ${logger9.dim(cred.envVar)}`);
|
|
2654
2988
|
}
|
|
2655
2989
|
if (isPrimary) {
|
|
2656
|
-
console.log(` ${
|
|
2990
|
+
console.log(` ${logger9.brand("\u2192 Primary source")}`);
|
|
2657
2991
|
}
|
|
2658
2992
|
console.log();
|
|
2659
2993
|
}
|
|
2660
2994
|
if (status.warnings && status.warnings.length > 0) {
|
|
2661
|
-
console.log(` ${
|
|
2995
|
+
console.log(` ${logger9.dim("Warnings:")}`);
|
|
2662
2996
|
for (const warning of status.warnings) {
|
|
2663
2997
|
console.log(` ! ${warning}`);
|
|
2664
2998
|
}
|
|
2665
2999
|
console.log();
|
|
2666
3000
|
}
|
|
2667
|
-
console.log(` ${
|
|
2668
|
-
console.log(` ${
|
|
3001
|
+
console.log(` ${logger9.dim("Tip:")} RAPID will automatically use detected`);
|
|
3002
|
+
console.log(` ${logger9.dim(" ")} credentials when launching AI agents.`);
|
|
2669
3003
|
console.log();
|
|
2670
3004
|
} catch (error) {
|
|
2671
|
-
|
|
3005
|
+
logger9.error(error instanceof Error ? error.message : String(error));
|
|
2672
3006
|
process.exit(1);
|
|
2673
3007
|
}
|
|
2674
3008
|
});
|
|
@@ -2714,34 +3048,34 @@ authCommand.command("env").description("Show environment variables for detected
|
|
|
2714
3048
|
return;
|
|
2715
3049
|
}
|
|
2716
3050
|
console.log();
|
|
2717
|
-
console.log(` ${
|
|
2718
|
-
console.log(` ${
|
|
3051
|
+
console.log(` ${logger9.brand("RAPID")} Auth Environment`);
|
|
3052
|
+
console.log(` ${logger9.dim("\u2500".repeat(24))}`);
|
|
2719
3053
|
console.log();
|
|
2720
3054
|
if (byProvider.size === 0) {
|
|
2721
|
-
console.log(` ${
|
|
3055
|
+
console.log(` ${logger9.dim("No credentials detected")}`);
|
|
2722
3056
|
console.log();
|
|
2723
3057
|
return;
|
|
2724
3058
|
}
|
|
2725
3059
|
for (const [provider, { envVar, masked }] of byProvider) {
|
|
2726
|
-
console.log(` ${
|
|
3060
|
+
console.log(` ${logger9.brand(provider)}`);
|
|
2727
3061
|
console.log(` ${envVar}=${masked}`);
|
|
2728
3062
|
console.log();
|
|
2729
3063
|
}
|
|
2730
|
-
console.log(` ${
|
|
3064
|
+
console.log(` ${logger9.dim("These will be automatically injected when running agents.")}`);
|
|
2731
3065
|
console.log();
|
|
2732
3066
|
} catch (error) {
|
|
2733
|
-
|
|
3067
|
+
logger9.error(error instanceof Error ? error.message : String(error));
|
|
2734
3068
|
process.exit(1);
|
|
2735
3069
|
}
|
|
2736
3070
|
});
|
|
2737
3071
|
|
|
2738
3072
|
// src/commands/mcp.ts
|
|
2739
3073
|
import { Command as Command9 } from "commander";
|
|
2740
|
-
import { writeFile as
|
|
2741
|
-
import { join as
|
|
3074
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
3075
|
+
import { join as join6 } from "path";
|
|
2742
3076
|
import {
|
|
2743
3077
|
loadConfig as loadConfig7,
|
|
2744
|
-
logger as
|
|
3078
|
+
logger as logger10,
|
|
2745
3079
|
getMcpServers,
|
|
2746
3080
|
getMcpServerStatus,
|
|
2747
3081
|
addMcpServerFromTemplate as addMcpServerFromTemplate2,
|
|
@@ -2752,15 +3086,16 @@ import {
|
|
|
2752
3086
|
writeMcpConfig as writeMcpConfig2,
|
|
2753
3087
|
writeOpenCodeConfig as writeOpenCodeConfig2,
|
|
2754
3088
|
MCP_SERVER_TEMPLATES as MCP_SERVER_TEMPLATES2,
|
|
2755
|
-
getMcpTemplate
|
|
3089
|
+
getMcpTemplate,
|
|
3090
|
+
formatJson as formatJson5
|
|
2756
3091
|
} from "@a3t/rapid-core";
|
|
2757
3092
|
import ora8 from "ora";
|
|
2758
3093
|
var mcpCommand = new Command9("mcp").description(
|
|
2759
3094
|
"Manage MCP (Model Context Protocol) servers"
|
|
2760
3095
|
);
|
|
2761
3096
|
async function saveConfig(rootDir, config) {
|
|
2762
|
-
const configPath =
|
|
2763
|
-
await
|
|
3097
|
+
const configPath = join6(rootDir, "rapid.json");
|
|
3098
|
+
await writeFile6(configPath, await formatJson5(config), "utf-8");
|
|
2764
3099
|
}
|
|
2765
3100
|
mcpCommand.command("list").description("List configured MCP servers").option("--json", "Output as JSON").option("--templates", "Show available templates instead of configured servers").action(async (options) => {
|
|
2766
3101
|
try {
|
|
@@ -2770,23 +3105,23 @@ mcpCommand.command("list").description("List configured MCP servers").option("--
|
|
|
2770
3105
|
return;
|
|
2771
3106
|
}
|
|
2772
3107
|
console.log();
|
|
2773
|
-
console.log(` ${
|
|
2774
|
-
console.log(` ${
|
|
3108
|
+
console.log(` ${logger10.brand("Available MCP Server Templates")}`);
|
|
3109
|
+
console.log(` ${logger10.dim("\u2500".repeat(40))}`);
|
|
2775
3110
|
console.log();
|
|
2776
3111
|
for (const [name, template] of Object.entries(MCP_SERVER_TEMPLATES2)) {
|
|
2777
|
-
const typeLabel = template.type === "remote" ?
|
|
2778
|
-
const secretsLabel = template.requiredSecrets.length > 0 ?
|
|
2779
|
-
console.log(` ${
|
|
3112
|
+
const typeLabel = template.type === "remote" ? logger10.dim("(remote)") : logger10.dim("(stdio)");
|
|
3113
|
+
const secretsLabel = template.requiredSecrets.length > 0 ? logger10.dim(` - requires: ${template.requiredSecrets.join(", ")}`) : logger10.dim(" - no secrets required");
|
|
3114
|
+
console.log(` ${logger10.brand("\u2022")} ${name} ${typeLabel}`);
|
|
2780
3115
|
console.log(` ${template.description}${secretsLabel}`);
|
|
2781
3116
|
console.log();
|
|
2782
3117
|
}
|
|
2783
|
-
|
|
3118
|
+
logger10.info(`Use ${logger10.brand("rapid mcp add <name>")} to add a server`);
|
|
2784
3119
|
console.log();
|
|
2785
3120
|
return;
|
|
2786
3121
|
}
|
|
2787
3122
|
const loaded = await loadConfig7();
|
|
2788
3123
|
if (!loaded) {
|
|
2789
|
-
|
|
3124
|
+
logger10.error("No rapid.json found. Run `rapid init` first.");
|
|
2790
3125
|
process.exit(1);
|
|
2791
3126
|
}
|
|
2792
3127
|
const { config } = loaded;
|
|
@@ -2796,22 +3131,22 @@ mcpCommand.command("list").description("List configured MCP servers").option("--
|
|
|
2796
3131
|
return;
|
|
2797
3132
|
}
|
|
2798
3133
|
console.log();
|
|
2799
|
-
console.log(` ${
|
|
2800
|
-
console.log(` ${
|
|
3134
|
+
console.log(` ${logger10.brand("MCP Servers")}`);
|
|
3135
|
+
console.log(` ${logger10.dim("\u2500".repeat(40))}`);
|
|
2801
3136
|
console.log();
|
|
2802
3137
|
if (servers.length === 0) {
|
|
2803
|
-
console.log(` ${
|
|
3138
|
+
console.log(` ${logger10.dim("No MCP servers configured")}`);
|
|
2804
3139
|
console.log();
|
|
2805
|
-
|
|
2806
|
-
|
|
3140
|
+
logger10.info(`Use ${logger10.brand("rapid mcp add <name>")} to add a server`);
|
|
3141
|
+
logger10.info(`Use ${logger10.brand("rapid mcp list --templates")} to see available templates`);
|
|
2807
3142
|
console.log();
|
|
2808
3143
|
return;
|
|
2809
3144
|
}
|
|
2810
3145
|
for (const server of servers) {
|
|
2811
|
-
const icon = server.enabled ?
|
|
2812
|
-
const typeLabel = server.type === "remote" ?
|
|
2813
|
-
const statusLabel = server.enabled ? "" :
|
|
2814
|
-
const location = server.type === "remote" ?
|
|
3146
|
+
const icon = server.enabled ? logger10.brand("\u2713") : logger10.dim("\u25CB");
|
|
3147
|
+
const typeLabel = server.type === "remote" ? logger10.dim("(remote)") : logger10.dim("(stdio)");
|
|
3148
|
+
const statusLabel = server.enabled ? "" : logger10.dim(" [disabled]");
|
|
3149
|
+
const location = server.type === "remote" ? logger10.dim(server.url || "") : logger10.dim(server.command || "");
|
|
2815
3150
|
console.log(` ${icon} ${server.name} ${typeLabel}${statusLabel}`);
|
|
2816
3151
|
if (location) {
|
|
2817
3152
|
console.log(` ${location}`);
|
|
@@ -2819,7 +3154,7 @@ mcpCommand.command("list").description("List configured MCP servers").option("--
|
|
|
2819
3154
|
console.log();
|
|
2820
3155
|
}
|
|
2821
3156
|
} catch (error) {
|
|
2822
|
-
|
|
3157
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
2823
3158
|
process.exit(1);
|
|
2824
3159
|
}
|
|
2825
3160
|
});
|
|
@@ -2836,7 +3171,7 @@ mcpCommand.command("add").description("Add an MCP server").argument("<name>", "S
|
|
|
2836
3171
|
const existingServers = getMcpServers(config);
|
|
2837
3172
|
if (existingServers.some((s) => s.name === name)) {
|
|
2838
3173
|
spinner.fail(`MCP server '${name}' already exists`);
|
|
2839
|
-
|
|
3174
|
+
logger10.info(`Use ${logger10.brand(`rapid mcp remove ${name}`)} to remove it first`);
|
|
2840
3175
|
process.exit(1);
|
|
2841
3176
|
}
|
|
2842
3177
|
const template = getMcpTemplate(name);
|
|
@@ -2869,8 +3204,8 @@ mcpCommand.command("add").description("Add an MCP server").argument("<name>", "S
|
|
|
2869
3204
|
config = addMcpServerFromTemplate2(config, name);
|
|
2870
3205
|
} else {
|
|
2871
3206
|
spinner.fail(`Unknown MCP server template: ${name}`);
|
|
2872
|
-
|
|
2873
|
-
|
|
3207
|
+
logger10.info(`Use ${logger10.brand("rapid mcp list --templates")} to see available templates`);
|
|
3208
|
+
logger10.info("Or specify --type, --url, or --command for a custom server");
|
|
2874
3209
|
process.exit(1);
|
|
2875
3210
|
}
|
|
2876
3211
|
await saveConfig(rootDir, config);
|
|
@@ -2879,18 +3214,18 @@ mcpCommand.command("add").description("Add an MCP server").argument("<name>", "S
|
|
|
2879
3214
|
spinner.succeed(`Added MCP server '${name}'`);
|
|
2880
3215
|
console.log();
|
|
2881
3216
|
if (template?.requiredSecrets.length) {
|
|
2882
|
-
|
|
3217
|
+
logger10.info("Required secrets:");
|
|
2883
3218
|
for (const secret of template.requiredSecrets) {
|
|
2884
3219
|
const ref = template.secretReferences?.[secret];
|
|
2885
|
-
console.log(` ${
|
|
3220
|
+
console.log(` ${logger10.brand("\u2022")} ${secret}${ref ? logger10.dim(` (${ref})`) : ""}`);
|
|
2886
3221
|
}
|
|
2887
3222
|
console.log();
|
|
2888
|
-
|
|
3223
|
+
logger10.info(`Add these to ${logger10.brand("rapid.json")} secrets.items section`);
|
|
2889
3224
|
console.log();
|
|
2890
3225
|
}
|
|
2891
3226
|
} catch (error) {
|
|
2892
3227
|
spinner.fail("Failed to add MCP server");
|
|
2893
|
-
|
|
3228
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
2894
3229
|
process.exit(1);
|
|
2895
3230
|
}
|
|
2896
3231
|
});
|
|
@@ -2912,7 +3247,7 @@ mcpCommand.command("remove").description("Remove an MCP server").argument("<name
|
|
|
2912
3247
|
console.log();
|
|
2913
3248
|
} catch (error) {
|
|
2914
3249
|
spinner.fail("Failed to remove MCP server");
|
|
2915
|
-
|
|
3250
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
2916
3251
|
process.exit(1);
|
|
2917
3252
|
}
|
|
2918
3253
|
});
|
|
@@ -2934,7 +3269,7 @@ mcpCommand.command("enable").description("Enable a disabled MCP server").argumen
|
|
|
2934
3269
|
console.log();
|
|
2935
3270
|
} catch (error) {
|
|
2936
3271
|
spinner.fail("Failed to enable MCP server");
|
|
2937
|
-
|
|
3272
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
2938
3273
|
process.exit(1);
|
|
2939
3274
|
}
|
|
2940
3275
|
});
|
|
@@ -2956,7 +3291,7 @@ mcpCommand.command("disable").description("Disable an MCP server (without removi
|
|
|
2956
3291
|
console.log();
|
|
2957
3292
|
} catch (error) {
|
|
2958
3293
|
spinner.fail("Failed to disable MCP server");
|
|
2959
|
-
|
|
3294
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
2960
3295
|
process.exit(1);
|
|
2961
3296
|
}
|
|
2962
3297
|
});
|
|
@@ -2964,7 +3299,7 @@ mcpCommand.command("status").description("Show MCP server status").option("--jso
|
|
|
2964
3299
|
try {
|
|
2965
3300
|
const loaded = await loadConfig7();
|
|
2966
3301
|
if (!loaded) {
|
|
2967
|
-
|
|
3302
|
+
logger10.error("No rapid.json found. Run `rapid init` first.");
|
|
2968
3303
|
process.exit(1);
|
|
2969
3304
|
}
|
|
2970
3305
|
const { config } = loaded;
|
|
@@ -2974,11 +3309,11 @@ mcpCommand.command("status").description("Show MCP server status").option("--jso
|
|
|
2974
3309
|
return;
|
|
2975
3310
|
}
|
|
2976
3311
|
console.log();
|
|
2977
|
-
console.log(` ${
|
|
2978
|
-
console.log(` ${
|
|
3312
|
+
console.log(` ${logger10.brand("MCP Server Status")}`);
|
|
3313
|
+
console.log(` ${logger10.dim("\u2500".repeat(40))}`);
|
|
2979
3314
|
console.log();
|
|
2980
3315
|
if (servers.length === 0) {
|
|
2981
|
-
console.log(` ${
|
|
3316
|
+
console.log(` ${logger10.dim("No MCP servers configured")}`);
|
|
2982
3317
|
console.log();
|
|
2983
3318
|
return;
|
|
2984
3319
|
}
|
|
@@ -2990,24 +3325,24 @@ mcpCommand.command("status").description("Show MCP server status").option("--jso
|
|
|
2990
3325
|
} else {
|
|
2991
3326
|
disabledCount++;
|
|
2992
3327
|
}
|
|
2993
|
-
const icon = server.status === "enabled" ?
|
|
2994
|
-
const statusLabel = server.status === "enabled" ? "enabled" : server.status === "disabled" ?
|
|
3328
|
+
const icon = server.status === "enabled" ? logger10.brand("\u2713") : server.status === "disabled" ? logger10.dim("\u25CB") : "\u2717";
|
|
3329
|
+
const statusLabel = server.status === "enabled" ? "enabled" : server.status === "disabled" ? logger10.dim("disabled") : logger10.dim(`error: ${server.error}`);
|
|
2995
3330
|
const typeLabel = server.type === "remote" ? "remote" : "stdio";
|
|
2996
3331
|
console.log(` ${icon} ${server.name}`);
|
|
2997
|
-
console.log(` ${
|
|
2998
|
-
console.log(` ${
|
|
3332
|
+
console.log(` ${logger10.dim("Type:")} ${typeLabel}`);
|
|
3333
|
+
console.log(` ${logger10.dim("Status:")} ${statusLabel}`);
|
|
2999
3334
|
if (server.url) {
|
|
3000
|
-
console.log(` ${
|
|
3335
|
+
console.log(` ${logger10.dim("URL:")} ${server.url}`);
|
|
3001
3336
|
}
|
|
3002
3337
|
if (server.command) {
|
|
3003
|
-
console.log(` ${
|
|
3338
|
+
console.log(` ${logger10.dim("Cmd:")} ${server.command}`);
|
|
3004
3339
|
}
|
|
3005
3340
|
console.log();
|
|
3006
3341
|
}
|
|
3007
|
-
console.log(` ${
|
|
3342
|
+
console.log(` ${logger10.dim("Summary:")} ${enabledCount} enabled, ${disabledCount} disabled`);
|
|
3008
3343
|
console.log();
|
|
3009
3344
|
} catch (error) {
|
|
3010
|
-
|
|
3345
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
3011
3346
|
process.exit(1);
|
|
3012
3347
|
}
|
|
3013
3348
|
});
|
|
@@ -3026,15 +3361,15 @@ mcpCommand.command("sync").description("Regenerate .mcp.json and opencode.json f
|
|
|
3026
3361
|
const enabledCount = servers.filter((s) => s.enabled).length;
|
|
3027
3362
|
spinner.succeed("MCP configuration synced");
|
|
3028
3363
|
console.log();
|
|
3029
|
-
console.log(` ${
|
|
3030
|
-
console.log(` ${
|
|
3031
|
-
console.log(` ${
|
|
3364
|
+
console.log(` ${logger10.dim("Files updated:")}`);
|
|
3365
|
+
console.log(` ${logger10.brand("\u2022")} .mcp.json`);
|
|
3366
|
+
console.log(` ${logger10.brand("\u2022")} opencode.json`);
|
|
3032
3367
|
console.log();
|
|
3033
|
-
console.log(` ${
|
|
3368
|
+
console.log(` ${logger10.dim("Servers:")} ${enabledCount} enabled`);
|
|
3034
3369
|
console.log();
|
|
3035
3370
|
} catch (error) {
|
|
3036
3371
|
spinner.fail("Failed to sync MCP configuration");
|
|
3037
|
-
|
|
3372
|
+
logger10.error(error instanceof Error ? error.message : String(error));
|
|
3038
3373
|
process.exit(1);
|
|
3039
3374
|
}
|
|
3040
3375
|
});
|
|
@@ -3046,25 +3381,143 @@ function collectHeaders(value, previous) {
|
|
|
3046
3381
|
return previous;
|
|
3047
3382
|
}
|
|
3048
3383
|
|
|
3049
|
-
// src/commands/
|
|
3384
|
+
// src/commands/context.ts
|
|
3050
3385
|
import { Command as Command10 } from "commander";
|
|
3386
|
+
import { loadConfig as loadConfig8, assembleContext as assembleContext2, logger as logger11 } from "@a3t/rapid-core";
|
|
3387
|
+
import ora9 from "ora";
|
|
3388
|
+
var contextCommand = new Command10("context").description("Show or inject project context from rapid.json").argument("[action]", "Action: show (default) or inject", "show").option("--json", "Output as JSON").action(async (action, options) => {
|
|
3389
|
+
try {
|
|
3390
|
+
const spinner = ora9("Loading configuration...").start();
|
|
3391
|
+
const loaded = await loadConfig8();
|
|
3392
|
+
if (!loaded) {
|
|
3393
|
+
spinner.fail("No rapid.json found. Run `rapid init` first.");
|
|
3394
|
+
process.exit(1);
|
|
3395
|
+
}
|
|
3396
|
+
const { config, rootDir } = loaded;
|
|
3397
|
+
spinner.stop();
|
|
3398
|
+
if (!config.context?.files?.length && !config.context?.dirs?.length) {
|
|
3399
|
+
if (action === "inject") {
|
|
3400
|
+
return;
|
|
3401
|
+
}
|
|
3402
|
+
logger11.info("No context files or directories configured.");
|
|
3403
|
+
logger11.blank();
|
|
3404
|
+
logger11.dim("Add files or directories to rapid.json:");
|
|
3405
|
+
logger11.dim(' "context": {');
|
|
3406
|
+
logger11.dim(' "files": ["README.md", "docs/architecture.md"],');
|
|
3407
|
+
logger11.dim(' "dirs": ["docs/"]');
|
|
3408
|
+
logger11.dim(" }");
|
|
3409
|
+
return;
|
|
3410
|
+
}
|
|
3411
|
+
const assembled = await assembleContext2(rootDir, config.context);
|
|
3412
|
+
if (action === "inject") {
|
|
3413
|
+
if (assembled.content) {
|
|
3414
|
+
console.log(assembled.content);
|
|
3415
|
+
}
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
if (options.json) {
|
|
3419
|
+
console.log(
|
|
3420
|
+
JSON.stringify(
|
|
3421
|
+
{
|
|
3422
|
+
files: assembled.files.map((f) => ({
|
|
3423
|
+
path: f.relativePath,
|
|
3424
|
+
size: f.size,
|
|
3425
|
+
truncated: f.truncated
|
|
3426
|
+
})),
|
|
3427
|
+
totalSize: assembled.totalSize,
|
|
3428
|
+
skippedFiles: assembled.skippedFiles.map((f) => ({
|
|
3429
|
+
path: f.path,
|
|
3430
|
+
reason: f.reason
|
|
3431
|
+
}))
|
|
3432
|
+
},
|
|
3433
|
+
null,
|
|
3434
|
+
2
|
|
3435
|
+
)
|
|
3436
|
+
);
|
|
3437
|
+
return;
|
|
3438
|
+
}
|
|
3439
|
+
logger11.header("Context Configuration");
|
|
3440
|
+
logger11.blank();
|
|
3441
|
+
if (config.context.files?.length) {
|
|
3442
|
+
logger11.info("Configured files:");
|
|
3443
|
+
for (const file of config.context.files) {
|
|
3444
|
+
console.log(` ${logger11.dim("\u2022")} ${file}`);
|
|
3445
|
+
}
|
|
3446
|
+
logger11.blank();
|
|
3447
|
+
}
|
|
3448
|
+
if (config.context.dirs?.length) {
|
|
3449
|
+
logger11.info("Configured directories:");
|
|
3450
|
+
for (const dir of config.context.dirs) {
|
|
3451
|
+
console.log(` ${logger11.dim("\u2022")} ${dir}`);
|
|
3452
|
+
}
|
|
3453
|
+
logger11.blank();
|
|
3454
|
+
}
|
|
3455
|
+
if (config.context.exclude?.length) {
|
|
3456
|
+
logger11.info("Exclude patterns:");
|
|
3457
|
+
for (const pattern of config.context.exclude) {
|
|
3458
|
+
console.log(` ${logger11.dim("\u2022")} ${pattern}`);
|
|
3459
|
+
}
|
|
3460
|
+
logger11.blank();
|
|
3461
|
+
}
|
|
3462
|
+
logger11.info(`Assembled ${assembled.files.length} file(s):`);
|
|
3463
|
+
for (const file of assembled.files) {
|
|
3464
|
+
const sizeKb = (file.size / 1024).toFixed(1);
|
|
3465
|
+
console.log(` ${logger11.brand("\u2022")} ${file.relativePath} ${logger11.dim(`(${sizeKb}KB)`)}`);
|
|
3466
|
+
}
|
|
3467
|
+
const totalKb = (assembled.totalSize / 1024).toFixed(1);
|
|
3468
|
+
logger11.blank();
|
|
3469
|
+
logger11.dim(`Total size: ${totalKb}KB`);
|
|
3470
|
+
if (assembled.skippedFiles.length > 0) {
|
|
3471
|
+
logger11.blank();
|
|
3472
|
+
logger11.info(`Skipped ${assembled.skippedFiles.length} file(s):`);
|
|
3473
|
+
for (const skipped of assembled.skippedFiles) {
|
|
3474
|
+
const reasonText = getSkipReasonText(skipped.reason);
|
|
3475
|
+
console.log(` ${logger11.dim("\u2022")} ${skipped.path} ${logger11.dim(`(${reasonText})`)}`);
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
} catch (error) {
|
|
3479
|
+
logger11.error(error instanceof Error ? error.message : String(error));
|
|
3480
|
+
process.exit(1);
|
|
3481
|
+
}
|
|
3482
|
+
});
|
|
3483
|
+
function getSkipReasonText(reason) {
|
|
3484
|
+
switch (reason) {
|
|
3485
|
+
case "missing":
|
|
3486
|
+
return "file not found";
|
|
3487
|
+
case "binary":
|
|
3488
|
+
return "binary file";
|
|
3489
|
+
case "too-large":
|
|
3490
|
+
return "exceeds size limit";
|
|
3491
|
+
case "excluded":
|
|
3492
|
+
return "excluded by pattern";
|
|
3493
|
+
case "directory":
|
|
3494
|
+
return "is a directory";
|
|
3495
|
+
case "error":
|
|
3496
|
+
return "read error";
|
|
3497
|
+
default:
|
|
3498
|
+
return reason;
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
|
|
3502
|
+
// src/commands/update.ts
|
|
3503
|
+
import { Command as Command11 } from "commander";
|
|
3051
3504
|
|
|
3052
3505
|
// src/utils/update-checker.ts
|
|
3053
3506
|
import updateNotifier from "update-notifier";
|
|
3054
3507
|
import semver from "semver";
|
|
3055
3508
|
import { execa as execa3 } from "execa";
|
|
3056
|
-
import { logger as
|
|
3509
|
+
import { logger as logger12 } from "@a3t/rapid-core";
|
|
3057
3510
|
import chalk from "chalk";
|
|
3058
3511
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
3059
3512
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3060
|
-
import { dirname as dirname3, join as
|
|
3513
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
3061
3514
|
import prompts from "prompts";
|
|
3062
3515
|
var __dirname = dirname3(fileURLToPath2(import.meta.url));
|
|
3063
3516
|
function loadPackageJson() {
|
|
3064
3517
|
const paths = [
|
|
3065
|
-
|
|
3518
|
+
join7(__dirname, "../package.json"),
|
|
3066
3519
|
// bundled: dist/ -> package root
|
|
3067
|
-
|
|
3520
|
+
join7(__dirname, "../../package.json")
|
|
3068
3521
|
// source: src/utils/ -> package root
|
|
3069
3522
|
];
|
|
3070
3523
|
for (const p of paths) {
|
|
@@ -3120,9 +3573,9 @@ var UpdateChecker = class {
|
|
|
3120
3573
|
if (!this.notifier.update) return;
|
|
3121
3574
|
const { current, latest } = this.notifier.update;
|
|
3122
3575
|
const updateType = this.getUpdateType(current, latest);
|
|
3123
|
-
|
|
3576
|
+
logger12.info(`Update available: ${logger12.dim(current)} \u2192 ${chalk.green(latest)}`);
|
|
3124
3577
|
if (updateType === "major") {
|
|
3125
|
-
|
|
3578
|
+
logger12.warn("This is a major version update with breaking changes.");
|
|
3126
3579
|
}
|
|
3127
3580
|
}
|
|
3128
3581
|
/**
|
|
@@ -3130,20 +3583,20 @@ var UpdateChecker = class {
|
|
|
3130
3583
|
*/
|
|
3131
3584
|
async verifySignatures() {
|
|
3132
3585
|
try {
|
|
3133
|
-
|
|
3586
|
+
logger12.info("Verifying package signatures...");
|
|
3134
3587
|
const result = await execa3("npm", ["audit", "signatures"], {
|
|
3135
3588
|
reject: false
|
|
3136
3589
|
});
|
|
3137
3590
|
if (result.exitCode === 0) {
|
|
3138
|
-
|
|
3591
|
+
logger12.success("Package signatures verified successfully");
|
|
3139
3592
|
return true;
|
|
3140
3593
|
} else {
|
|
3141
|
-
|
|
3142
|
-
|
|
3594
|
+
logger12.warn("Package signature verification returned warnings");
|
|
3595
|
+
logger12.debug(result.stdout || result.stderr);
|
|
3143
3596
|
return true;
|
|
3144
3597
|
}
|
|
3145
3598
|
} catch {
|
|
3146
|
-
|
|
3599
|
+
logger12.debug("Signature verification not available (requires npm >= 9)");
|
|
3147
3600
|
return true;
|
|
3148
3601
|
}
|
|
3149
3602
|
}
|
|
@@ -3152,16 +3605,16 @@ var UpdateChecker = class {
|
|
|
3152
3605
|
*/
|
|
3153
3606
|
async performUpdate() {
|
|
3154
3607
|
try {
|
|
3155
|
-
|
|
3608
|
+
logger12.info("Updating RAPID CLI...");
|
|
3156
3609
|
await execa3("npm", ["install", "-g", `${this.packageName}@latest`], {
|
|
3157
3610
|
stdio: "inherit"
|
|
3158
3611
|
});
|
|
3159
3612
|
await this.verifySignatures();
|
|
3160
|
-
|
|
3161
|
-
|
|
3613
|
+
logger12.success("RAPID CLI updated successfully!");
|
|
3614
|
+
logger12.info("Package published with npm provenance - cryptographically verified");
|
|
3162
3615
|
return true;
|
|
3163
3616
|
} catch (error) {
|
|
3164
|
-
|
|
3617
|
+
logger12.error("Failed to update RAPID CLI:", error);
|
|
3165
3618
|
return false;
|
|
3166
3619
|
}
|
|
3167
3620
|
}
|
|
@@ -3174,7 +3627,7 @@ var UpdateChecker = class {
|
|
|
3174
3627
|
if (!updateInfo) return;
|
|
3175
3628
|
this.showNotification();
|
|
3176
3629
|
if (updateInfo.type === "major") {
|
|
3177
|
-
|
|
3630
|
+
logger12.warn(
|
|
3178
3631
|
`This is a major version update (${updateInfo.current} \u2192 ${updateInfo.latest}) that may contain breaking changes.`
|
|
3179
3632
|
);
|
|
3180
3633
|
try {
|
|
@@ -3185,20 +3638,20 @@ var UpdateChecker = class {
|
|
|
3185
3638
|
initial: false
|
|
3186
3639
|
});
|
|
3187
3640
|
if (response.shouldUpdate) {
|
|
3188
|
-
|
|
3641
|
+
logger12.info(`Updating to ${updateInfo.latest} (major version)...`);
|
|
3189
3642
|
await this.performUpdate();
|
|
3190
3643
|
} else {
|
|
3191
|
-
|
|
3192
|
-
|
|
3644
|
+
logger12.info("Skipping major version update.");
|
|
3645
|
+
logger12.info('You can update later with "rapid update --force"');
|
|
3193
3646
|
}
|
|
3194
3647
|
} catch {
|
|
3195
|
-
|
|
3648
|
+
logger12.info(
|
|
3196
3649
|
'Run "rapid update" to update manually, or use "rapid update --force" to update automatically.'
|
|
3197
3650
|
);
|
|
3198
3651
|
}
|
|
3199
3652
|
return;
|
|
3200
3653
|
}
|
|
3201
|
-
|
|
3654
|
+
logger12.info(`Auto-updating to ${updateInfo.latest} (${updateInfo.type} version)...`);
|
|
3202
3655
|
await this.performUpdate();
|
|
3203
3656
|
}
|
|
3204
3657
|
/**
|
|
@@ -3206,7 +3659,7 @@ var UpdateChecker = class {
|
|
|
3206
3659
|
*/
|
|
3207
3660
|
async forceUpdate() {
|
|
3208
3661
|
if (!this.hasUpdate()) {
|
|
3209
|
-
|
|
3662
|
+
logger12.info("No updates available.");
|
|
3210
3663
|
return;
|
|
3211
3664
|
}
|
|
3212
3665
|
const updateInfo = this.getUpdateInfo();
|
|
@@ -3219,68 +3672,68 @@ var UpdateChecker = class {
|
|
|
3219
3672
|
var updateChecker = new UpdateChecker();
|
|
3220
3673
|
|
|
3221
3674
|
// src/commands/update.ts
|
|
3222
|
-
import { logger as
|
|
3223
|
-
var updateCommand = new
|
|
3675
|
+
import { logger as logger13 } from "@a3t/rapid-core";
|
|
3676
|
+
var updateCommand = new Command11("update").description("Check for and apply updates").option("--check", "Check for updates only").option("--force", "Force update even for major versions").action(async (options) => {
|
|
3224
3677
|
try {
|
|
3225
3678
|
if (options.check) {
|
|
3226
|
-
|
|
3679
|
+
logger13.header("Checking for updates...");
|
|
3227
3680
|
if (!updateChecker.hasUpdate()) {
|
|
3228
|
-
|
|
3681
|
+
logger13.success("You are using the latest version!");
|
|
3229
3682
|
return;
|
|
3230
3683
|
}
|
|
3231
3684
|
const updateInfo2 = updateChecker.getUpdateInfo();
|
|
3232
3685
|
if (updateInfo2) {
|
|
3233
3686
|
updateChecker.showNotification();
|
|
3234
3687
|
if (updateInfo2.type === "major") {
|
|
3235
|
-
|
|
3236
|
-
|
|
3688
|
+
logger13.warn("This is a major version update with breaking changes.");
|
|
3689
|
+
logger13.info('Use "rapid update --force" to update.');
|
|
3237
3690
|
} else {
|
|
3238
|
-
|
|
3691
|
+
logger13.info('Use "rapid update" to apply the update.');
|
|
3239
3692
|
}
|
|
3240
3693
|
}
|
|
3241
3694
|
return;
|
|
3242
3695
|
}
|
|
3243
3696
|
if (!updateChecker.hasUpdate()) {
|
|
3244
|
-
|
|
3697
|
+
logger13.success("You are already using the latest version!");
|
|
3245
3698
|
return;
|
|
3246
3699
|
}
|
|
3247
3700
|
const updateInfo = updateChecker.getUpdateInfo();
|
|
3248
3701
|
if (updateInfo && updateInfo.type === "major" && !options.force) {
|
|
3249
|
-
|
|
3250
|
-
|
|
3702
|
+
logger13.warn("This is a major version update with breaking changes.");
|
|
3703
|
+
logger13.info("Use --force to update anyway.");
|
|
3251
3704
|
return;
|
|
3252
3705
|
}
|
|
3253
3706
|
await updateChecker.forceUpdate();
|
|
3254
3707
|
} catch (error) {
|
|
3255
|
-
|
|
3708
|
+
logger13.error("Update failed:", error);
|
|
3256
3709
|
process.exit(1);
|
|
3257
3710
|
}
|
|
3258
3711
|
});
|
|
3259
3712
|
|
|
3260
3713
|
// src/commands/worktree.ts
|
|
3261
|
-
import { Command as
|
|
3262
|
-
import { logger as
|
|
3263
|
-
import
|
|
3714
|
+
import { Command as Command12 } from "commander";
|
|
3715
|
+
import { logger as logger14 } from "@a3t/rapid-core";
|
|
3716
|
+
import ora10 from "ora";
|
|
3264
3717
|
function formatWorktree(wt, currentPath) {
|
|
3265
3718
|
const isCurrent = wt.path === currentPath;
|
|
3266
|
-
const marker = isCurrent ?
|
|
3719
|
+
const marker = isCurrent ? logger14.brand("*") : " ";
|
|
3267
3720
|
const status = [];
|
|
3268
3721
|
if (wt.isMain) status.push("main");
|
|
3269
3722
|
if (wt.locked) status.push("locked");
|
|
3270
3723
|
if (wt.prunable) status.push("prunable");
|
|
3271
3724
|
if (!wt.exists) status.push("missing");
|
|
3272
|
-
const statusStr = status.length > 0 ?
|
|
3273
|
-
const branchStr = wt.branch ?
|
|
3725
|
+
const statusStr = status.length > 0 ? logger14.dim(` (${status.join(", ")})`) : "";
|
|
3726
|
+
const branchStr = wt.branch ? logger14.brand(wt.branch) : logger14.dim("detached");
|
|
3274
3727
|
const headShort = wt.head?.substring(0, 7) ?? "";
|
|
3275
3728
|
return `${marker} ${branchStr}${statusStr}
|
|
3276
|
-
${
|
|
3277
|
-
${
|
|
3729
|
+
${logger14.dim(wt.path)}
|
|
3730
|
+
${logger14.dim(`HEAD: ${headShort}`)}`;
|
|
3278
3731
|
}
|
|
3279
|
-
var listCommand = new
|
|
3732
|
+
var listCommand = new Command12("list").alias("ls").description("List all git worktrees").option("--json", "Output as JSON").action(async (options) => {
|
|
3280
3733
|
try {
|
|
3281
3734
|
const cwd = process.cwd();
|
|
3282
3735
|
if (!await isGitRepo(cwd)) {
|
|
3283
|
-
|
|
3736
|
+
logger14.error("Not a git repository");
|
|
3284
3737
|
process.exit(1);
|
|
3285
3738
|
}
|
|
3286
3739
|
const gitRoot = await getGitRoot(cwd);
|
|
@@ -3290,10 +3743,10 @@ var listCommand = new Command11("list").alias("ls").description("List all git wo
|
|
|
3290
3743
|
return;
|
|
3291
3744
|
}
|
|
3292
3745
|
if (worktrees.length === 0) {
|
|
3293
|
-
|
|
3746
|
+
logger14.info("No worktrees found");
|
|
3294
3747
|
return;
|
|
3295
3748
|
}
|
|
3296
|
-
|
|
3749
|
+
logger14.header("Git Worktrees");
|
|
3297
3750
|
console.log();
|
|
3298
3751
|
for (const wt of worktrees) {
|
|
3299
3752
|
console.log(formatWorktree(wt, gitRoot));
|
|
@@ -3301,15 +3754,15 @@ var listCommand = new Command11("list").alias("ls").description("List all git wo
|
|
|
3301
3754
|
}
|
|
3302
3755
|
const prunable = worktrees.filter((wt) => wt.prunable);
|
|
3303
3756
|
if (prunable.length > 0) {
|
|
3304
|
-
|
|
3757
|
+
logger14.warn(`${prunable.length} worktree(s) can be pruned. Run: rapid worktree prune`);
|
|
3305
3758
|
}
|
|
3306
3759
|
} catch (error) {
|
|
3307
|
-
|
|
3760
|
+
logger14.error(error instanceof Error ? error.message : String(error));
|
|
3308
3761
|
process.exit(1);
|
|
3309
3762
|
}
|
|
3310
3763
|
});
|
|
3311
|
-
var pruneCommand = new
|
|
3312
|
-
const spinner =
|
|
3764
|
+
var pruneCommand = new Command12("prune").description("Remove stale worktree references").option("--dry-run", "Show what would be pruned without removing").action(async (options) => {
|
|
3765
|
+
const spinner = ora10("Checking worktrees...").start();
|
|
3313
3766
|
try {
|
|
3314
3767
|
const cwd = process.cwd();
|
|
3315
3768
|
if (!await isGitRepo(cwd)) {
|
|
@@ -3326,7 +3779,7 @@ var pruneCommand = new Command11("prune").description("Remove stale worktree ref
|
|
|
3326
3779
|
if (options.dryRun) {
|
|
3327
3780
|
spinner.info(`Would prune ${prunable.length} worktree(s):`);
|
|
3328
3781
|
for (const wt of prunable) {
|
|
3329
|
-
console.log(` ${
|
|
3782
|
+
console.log(` ${logger14.dim("\u2022")} ${wt.path}`);
|
|
3330
3783
|
}
|
|
3331
3784
|
return;
|
|
3332
3785
|
}
|
|
@@ -3335,7 +3788,7 @@ var pruneCommand = new Command11("prune").description("Remove stale worktree ref
|
|
|
3335
3788
|
if (result.success) {
|
|
3336
3789
|
spinner.succeed(`Pruned ${result.pruned.length} worktree(s)`);
|
|
3337
3790
|
for (const path of result.pruned) {
|
|
3338
|
-
console.log(` ${
|
|
3791
|
+
console.log(` ${logger14.dim("\u2022")} ${path}`);
|
|
3339
3792
|
}
|
|
3340
3793
|
} else {
|
|
3341
3794
|
spinner.fail(`Failed to prune: ${result.error}`);
|
|
@@ -3346,8 +3799,8 @@ var pruneCommand = new Command11("prune").description("Remove stale worktree ref
|
|
|
3346
3799
|
process.exit(1);
|
|
3347
3800
|
}
|
|
3348
3801
|
});
|
|
3349
|
-
var removeCommand = new
|
|
3350
|
-
const spinner =
|
|
3802
|
+
var removeCommand = new Command12("remove").alias("rm").description("Remove a worktree").argument("<path-or-branch>", "Worktree path or branch name").option("-f, --force", "Force removal even if worktree is dirty").action(async (pathOrBranch, options) => {
|
|
3803
|
+
const spinner = ora10("Finding worktree...").start();
|
|
3351
3804
|
try {
|
|
3352
3805
|
const cwd = process.cwd();
|
|
3353
3806
|
if (!await isGitRepo(cwd)) {
|
|
@@ -3361,7 +3814,7 @@ var removeCommand = new Command11("remove").alias("rm").description("Remove a wo
|
|
|
3361
3814
|
);
|
|
3362
3815
|
if (!worktree) {
|
|
3363
3816
|
spinner.fail(`Worktree not found: ${pathOrBranch}`);
|
|
3364
|
-
|
|
3817
|
+
logger14.info("Available worktrees:");
|
|
3365
3818
|
for (const wt of worktrees) {
|
|
3366
3819
|
console.log(` ${wt.branch || wt.path}`);
|
|
3367
3820
|
}
|
|
@@ -3388,8 +3841,8 @@ var removeCommand = new Command11("remove").alias("rm").description("Remove a wo
|
|
|
3388
3841
|
process.exit(1);
|
|
3389
3842
|
}
|
|
3390
3843
|
});
|
|
3391
|
-
var cleanupCommand = new
|
|
3392
|
-
const spinner =
|
|
3844
|
+
var cleanupCommand = new Command12("cleanup").description("Remove worktrees for branches that have been merged").option("--dry-run", "Show what would be removed without removing").action(async (options) => {
|
|
3845
|
+
const spinner = ora10("Analyzing worktrees...").start();
|
|
3393
3846
|
try {
|
|
3394
3847
|
const cwd = process.cwd();
|
|
3395
3848
|
if (!await isGitRepo(cwd)) {
|
|
@@ -3406,10 +3859,10 @@ var cleanupCommand = new Command11("cleanup").description("Remove worktrees for
|
|
|
3406
3859
|
} else {
|
|
3407
3860
|
console.log(" Feature branch worktrees:");
|
|
3408
3861
|
for (const wt of nonMain) {
|
|
3409
|
-
console.log(` ${
|
|
3862
|
+
console.log(` ${logger14.dim("\u2022")} ${wt.branch} - ${wt.path}`);
|
|
3410
3863
|
}
|
|
3411
3864
|
console.log();
|
|
3412
|
-
|
|
3865
|
+
logger14.info("Run without --dry-run to remove worktrees for merged branches");
|
|
3413
3866
|
}
|
|
3414
3867
|
return;
|
|
3415
3868
|
}
|
|
@@ -3421,13 +3874,13 @@ var cleanupCommand = new Command11("cleanup").description("Remove worktrees for
|
|
|
3421
3874
|
}
|
|
3422
3875
|
spinner.succeed(`Cleaned up ${result.removed.length} worktree(s)`);
|
|
3423
3876
|
for (const path of result.removed) {
|
|
3424
|
-
console.log(` ${
|
|
3877
|
+
console.log(` ${logger14.dim("\u2022")} ${path}`);
|
|
3425
3878
|
}
|
|
3426
3879
|
if (result.errors.length > 0) {
|
|
3427
3880
|
console.log();
|
|
3428
|
-
|
|
3881
|
+
logger14.warn("Some worktrees could not be removed:");
|
|
3429
3882
|
for (const err of result.errors) {
|
|
3430
|
-
console.log(` ${
|
|
3883
|
+
console.log(` ${logger14.dim("\u2022")} ${err}`);
|
|
3431
3884
|
}
|
|
3432
3885
|
}
|
|
3433
3886
|
} catch (error) {
|
|
@@ -3435,32 +3888,32 @@ var cleanupCommand = new Command11("cleanup").description("Remove worktrees for
|
|
|
3435
3888
|
process.exit(1);
|
|
3436
3889
|
}
|
|
3437
3890
|
});
|
|
3438
|
-
var worktreeCommand = new
|
|
3891
|
+
var worktreeCommand = new Command12("worktree").alias("wt").description("Manage git worktrees for isolated development").addCommand(listCommand).addCommand(pruneCommand).addCommand(removeCommand).addCommand(cleanupCommand);
|
|
3439
3892
|
worktreeCommand.action(async () => {
|
|
3440
3893
|
await listCommand.parseAsync([], { from: "user" });
|
|
3441
3894
|
});
|
|
3442
3895
|
|
|
3443
3896
|
// src/commands/lima.ts
|
|
3444
|
-
import { Command as
|
|
3445
|
-
import { logger as
|
|
3446
|
-
import
|
|
3897
|
+
import { Command as Command13 } from "commander";
|
|
3898
|
+
import { logger as logger15 } from "@a3t/rapid-core";
|
|
3899
|
+
import ora11 from "ora";
|
|
3447
3900
|
async function checkLimaAvailable() {
|
|
3448
3901
|
if (!isMacOS()) {
|
|
3449
|
-
|
|
3902
|
+
logger15.error("Lima is only available on macOS");
|
|
3450
3903
|
return false;
|
|
3451
3904
|
}
|
|
3452
3905
|
if (!await hasLima()) {
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
console.log(` ${
|
|
3457
|
-
|
|
3458
|
-
|
|
3906
|
+
logger15.error("Lima is not installed");
|
|
3907
|
+
logger15.blank();
|
|
3908
|
+
logger15.info("Install Lima with:");
|
|
3909
|
+
console.log(` ${logger15.dim("$")} brew install lima`);
|
|
3910
|
+
logger15.blank();
|
|
3911
|
+
logger15.info("For more information: https://lima-vm.io");
|
|
3459
3912
|
return false;
|
|
3460
3913
|
}
|
|
3461
3914
|
return true;
|
|
3462
3915
|
}
|
|
3463
|
-
var statusCommand2 = new
|
|
3916
|
+
var statusCommand2 = new Command13("status").description("Show Lima VM status").option("--json", "Output as JSON").action(async (options) => {
|
|
3464
3917
|
if (!await checkLimaAvailable()) {
|
|
3465
3918
|
process.exit(1);
|
|
3466
3919
|
}
|
|
@@ -3470,43 +3923,43 @@ var statusCommand2 = new Command12("status").description("Show Lima VM status").
|
|
|
3470
3923
|
return;
|
|
3471
3924
|
}
|
|
3472
3925
|
if (!instance) {
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
console.log(` ${
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
console.log(` ${
|
|
3926
|
+
logger15.info(`Lima VM (${RAPID_LIMA_INSTANCE}) is not created`);
|
|
3927
|
+
logger15.blank();
|
|
3928
|
+
logger15.info("Start the VM with:");
|
|
3929
|
+
console.log(` ${logger15.dim("$")} rapid lima start`);
|
|
3930
|
+
logger15.blank();
|
|
3931
|
+
logger15.info("Or use:");
|
|
3932
|
+
console.log(` ${logger15.dim("$")} rapid dev --local`);
|
|
3480
3933
|
return;
|
|
3481
3934
|
}
|
|
3482
|
-
|
|
3935
|
+
logger15.header("Lima VM Status");
|
|
3483
3936
|
console.log();
|
|
3484
|
-
console.log(` ${
|
|
3937
|
+
console.log(` ${logger15.dim("Name:")} ${instance.name}`);
|
|
3485
3938
|
console.log(
|
|
3486
|
-
` ${
|
|
3939
|
+
` ${logger15.dim("Status:")} ${instance.status === "Running" ? logger15.brand(instance.status) : instance.status}`
|
|
3487
3940
|
);
|
|
3488
|
-
console.log(` ${
|
|
3489
|
-
console.log(` ${
|
|
3490
|
-
console.log(` ${
|
|
3491
|
-
console.log(` ${
|
|
3941
|
+
console.log(` ${logger15.dim("Arch:")} ${instance.arch}`);
|
|
3942
|
+
console.log(` ${logger15.dim("CPUs:")} ${instance.cpus}`);
|
|
3943
|
+
console.log(` ${logger15.dim("Memory:")} ${instance.memory}`);
|
|
3944
|
+
console.log(` ${logger15.dim("Disk:")} ${instance.disk}`);
|
|
3492
3945
|
if (instance.sshLocalPort) {
|
|
3493
|
-
console.log(` ${
|
|
3946
|
+
console.log(` ${logger15.dim("SSH Port:")} ${instance.sshLocalPort}`);
|
|
3494
3947
|
}
|
|
3495
3948
|
console.log();
|
|
3496
3949
|
if (instance.status === "Running") {
|
|
3497
|
-
|
|
3498
|
-
console.log(` ${
|
|
3950
|
+
logger15.info("To open a shell:");
|
|
3951
|
+
console.log(` ${logger15.dim("$")} rapid lima shell`);
|
|
3499
3952
|
} else {
|
|
3500
|
-
|
|
3501
|
-
console.log(` ${
|
|
3953
|
+
logger15.info("To start the VM:");
|
|
3954
|
+
console.log(` ${logger15.dim("$")} rapid lima start`);
|
|
3502
3955
|
}
|
|
3503
3956
|
console.log();
|
|
3504
3957
|
});
|
|
3505
|
-
var startCommand2 = new
|
|
3958
|
+
var startCommand2 = new Command13("start").description("Start the Lima VM").option("--cpus <n>", "Number of CPUs", "4").option("--memory <size>", "Memory size", "8GiB").option("--disk <size>", "Disk size", "50GiB").action(async (options) => {
|
|
3506
3959
|
if (!await checkLimaAvailable()) {
|
|
3507
3960
|
process.exit(1);
|
|
3508
3961
|
}
|
|
3509
|
-
const spinner =
|
|
3962
|
+
const spinner = ora11("Starting Lima VM...").start();
|
|
3510
3963
|
const projectDir = process.cwd();
|
|
3511
3964
|
const result = await startInstance(projectDir, {
|
|
3512
3965
|
cpus: parseInt(options.cpus, 10),
|
|
@@ -3516,56 +3969,56 @@ var startCommand2 = new Command12("start").description("Start the Lima VM").opti
|
|
|
3516
3969
|
});
|
|
3517
3970
|
if (!result.success) {
|
|
3518
3971
|
spinner.fail("Failed to start Lima VM");
|
|
3519
|
-
|
|
3972
|
+
logger15.error(result.error ?? "Unknown error");
|
|
3520
3973
|
process.exit(1);
|
|
3521
3974
|
}
|
|
3522
3975
|
spinner.succeed("Lima VM started");
|
|
3523
|
-
|
|
3524
|
-
const sshSpinner =
|
|
3976
|
+
logger15.blank();
|
|
3977
|
+
const sshSpinner = ora11("Checking SSH agent forwarding...").start();
|
|
3525
3978
|
const sshResult = await setupGitSsh();
|
|
3526
3979
|
if (sshResult.success) {
|
|
3527
3980
|
sshSpinner.succeed("SSH agent forwarding is working");
|
|
3528
3981
|
} else {
|
|
3529
3982
|
sshSpinner.warn("SSH agent forwarding may not be working");
|
|
3530
|
-
|
|
3983
|
+
logger15.dim(sshResult.error ?? "Make sure ssh-agent is running on the host");
|
|
3531
3984
|
}
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
console.log(` ${
|
|
3985
|
+
logger15.blank();
|
|
3986
|
+
logger15.info("To open a shell:");
|
|
3987
|
+
console.log(` ${logger15.dim("$")} rapid lima shell`);
|
|
3535
3988
|
console.log();
|
|
3536
3989
|
});
|
|
3537
|
-
var stopCommand2 = new
|
|
3990
|
+
var stopCommand2 = new Command13("stop").description("Stop the Lima VM").option("-f, --force", "Force stop").action(async (options) => {
|
|
3538
3991
|
if (!await checkLimaAvailable()) {
|
|
3539
3992
|
process.exit(1);
|
|
3540
3993
|
}
|
|
3541
3994
|
const instance = await getInstance();
|
|
3542
3995
|
if (!instance) {
|
|
3543
|
-
|
|
3996
|
+
logger15.info("Lima VM is not created");
|
|
3544
3997
|
return;
|
|
3545
3998
|
}
|
|
3546
3999
|
if (instance.status !== "Running") {
|
|
3547
|
-
|
|
4000
|
+
logger15.info("Lima VM is already stopped");
|
|
3548
4001
|
return;
|
|
3549
4002
|
}
|
|
3550
|
-
const spinner =
|
|
4003
|
+
const spinner = ora11("Stopping Lima VM...").start();
|
|
3551
4004
|
const result = await stopInstance(RAPID_LIMA_INSTANCE, {
|
|
3552
4005
|
force: options.force
|
|
3553
4006
|
});
|
|
3554
4007
|
if (!result.success) {
|
|
3555
4008
|
spinner.fail("Failed to stop Lima VM");
|
|
3556
|
-
|
|
4009
|
+
logger15.error(result.error ?? "Unknown error");
|
|
3557
4010
|
process.exit(1);
|
|
3558
4011
|
}
|
|
3559
4012
|
spinner.succeed("Lima VM stopped");
|
|
3560
4013
|
});
|
|
3561
|
-
var shellCommand = new
|
|
4014
|
+
var shellCommand = new Command13("shell").description("Open a shell in the Lima VM").option("-c, --command <cmd>", "Command to run instead of interactive shell").action(async (options) => {
|
|
3562
4015
|
if (!await checkLimaAvailable()) {
|
|
3563
4016
|
process.exit(1);
|
|
3564
4017
|
}
|
|
3565
4018
|
const instance = await getInstance();
|
|
3566
4019
|
if (!instance || instance.status !== "Running") {
|
|
3567
|
-
|
|
3568
|
-
|
|
4020
|
+
logger15.error("Lima VM is not running");
|
|
4021
|
+
logger15.info("Start with: rapid lima start");
|
|
3569
4022
|
process.exit(1);
|
|
3570
4023
|
}
|
|
3571
4024
|
await shellInLima({
|
|
@@ -3573,30 +4026,30 @@ var shellCommand = new Command12("shell").description("Open a shell in the Lima
|
|
|
3573
4026
|
command: options.command
|
|
3574
4027
|
});
|
|
3575
4028
|
});
|
|
3576
|
-
var deleteCommand = new
|
|
4029
|
+
var deleteCommand = new Command13("delete").description("Delete the Lima VM").option("-f, --force", "Force delete without confirmation").action(async (options) => {
|
|
3577
4030
|
if (!await checkLimaAvailable()) {
|
|
3578
4031
|
process.exit(1);
|
|
3579
4032
|
}
|
|
3580
4033
|
const instance = await getInstance();
|
|
3581
4034
|
if (!instance) {
|
|
3582
|
-
|
|
4035
|
+
logger15.info("Lima VM does not exist");
|
|
3583
4036
|
return;
|
|
3584
4037
|
}
|
|
3585
4038
|
if (!options.force) {
|
|
3586
|
-
|
|
3587
|
-
|
|
4039
|
+
logger15.warn("This will permanently delete the Lima VM and all its data.");
|
|
4040
|
+
logger15.info(`Use ${logger15.brand("--force")} to confirm deletion.`);
|
|
3588
4041
|
return;
|
|
3589
4042
|
}
|
|
3590
|
-
const spinner =
|
|
4043
|
+
const spinner = ora11("Deleting Lima VM...").start();
|
|
3591
4044
|
const result = await deleteInstance(RAPID_LIMA_INSTANCE, { force: true });
|
|
3592
4045
|
if (!result.success) {
|
|
3593
4046
|
spinner.fail("Failed to delete Lima VM");
|
|
3594
|
-
|
|
4047
|
+
logger15.error(result.error ?? "Unknown error");
|
|
3595
4048
|
process.exit(1);
|
|
3596
4049
|
}
|
|
3597
4050
|
spinner.succeed("Lima VM deleted");
|
|
3598
4051
|
});
|
|
3599
|
-
var listCommand2 = new
|
|
4052
|
+
var listCommand2 = new Command13("list").alias("ls").description("List all Lima instances").option("--json", "Output as JSON").action(async (options) => {
|
|
3600
4053
|
if (!await checkLimaAvailable()) {
|
|
3601
4054
|
process.exit(1);
|
|
3602
4055
|
}
|
|
@@ -3606,31 +4059,31 @@ var listCommand2 = new Command12("list").alias("ls").description("List all Lima
|
|
|
3606
4059
|
return;
|
|
3607
4060
|
}
|
|
3608
4061
|
if (instances.length === 0) {
|
|
3609
|
-
|
|
4062
|
+
logger15.info("No Lima instances found");
|
|
3610
4063
|
return;
|
|
3611
4064
|
}
|
|
3612
|
-
|
|
4065
|
+
logger15.header("Lima Instances");
|
|
3613
4066
|
console.log();
|
|
3614
4067
|
for (const inst of instances) {
|
|
3615
4068
|
const isRapid = inst.name === RAPID_LIMA_INSTANCE;
|
|
3616
|
-
const statusColor = inst.status === "Running" ?
|
|
4069
|
+
const statusColor = inst.status === "Running" ? logger15.brand : logger15.dim;
|
|
3617
4070
|
console.log(
|
|
3618
|
-
` ${isRapid ?
|
|
4071
|
+
` ${isRapid ? logger15.brand("*") : " "} ${inst.name} ${statusColor(`(${inst.status})`)}`
|
|
3619
4072
|
);
|
|
3620
|
-
console.log(` ${
|
|
4073
|
+
console.log(` ${logger15.dim(`${inst.cpus} CPUs, ${inst.memory}, ${inst.disk}`)}`);
|
|
3621
4074
|
}
|
|
3622
4075
|
console.log();
|
|
3623
4076
|
});
|
|
3624
|
-
var limaCommand = new
|
|
4077
|
+
var limaCommand = new Command13("lima").description("Manage Lima VM for local development (macOS)").addCommand(statusCommand2).addCommand(startCommand2).addCommand(stopCommand2).addCommand(shellCommand).addCommand(deleteCommand).addCommand(listCommand2);
|
|
3625
4078
|
limaCommand.action(async () => {
|
|
3626
4079
|
await statusCommand2.parseAsync([], { from: "user" });
|
|
3627
4080
|
});
|
|
3628
4081
|
|
|
3629
4082
|
// src/index.ts
|
|
3630
4083
|
var __dirname2 = dirname4(fileURLToPath3(import.meta.url));
|
|
3631
|
-
var packageJson2 = JSON.parse(readFileSync2(
|
|
4084
|
+
var packageJson2 = JSON.parse(readFileSync2(join8(__dirname2, "../package.json"), "utf-8"));
|
|
3632
4085
|
var VERSION = packageJson2.version;
|
|
3633
|
-
var program = new
|
|
4086
|
+
var program = new Command14();
|
|
3634
4087
|
program.name("rapid").description("AI-assisted development with dev containers").version(VERSION, "-v, --version", "Show version").option("--verbose", "Verbose output").option("-q, --quiet", "Minimal output").option("--config <path>", "Path to rapid.json").hook("preAction", async (thisCommand) => {
|
|
3635
4088
|
const opts = thisCommand.opts();
|
|
3636
4089
|
if (opts.verbose) {
|
|
@@ -3644,7 +4097,7 @@ program.name("rapid").description("AI-assisted development with dev containers")
|
|
|
3644
4097
|
try {
|
|
3645
4098
|
await updateChecker.checkAndUpdate();
|
|
3646
4099
|
} catch (error) {
|
|
3647
|
-
|
|
4100
|
+
logger16.debug("Update check failed:", error);
|
|
3648
4101
|
}
|
|
3649
4102
|
});
|
|
3650
4103
|
program.addCommand(initCommand);
|
|
@@ -3656,13 +4109,14 @@ program.addCommand(agentCommand);
|
|
|
3656
4109
|
program.addCommand(secretsCommand);
|
|
3657
4110
|
program.addCommand(authCommand);
|
|
3658
4111
|
program.addCommand(mcpCommand);
|
|
4112
|
+
program.addCommand(contextCommand);
|
|
3659
4113
|
program.addCommand(updateCommand);
|
|
3660
4114
|
program.addCommand(worktreeCommand);
|
|
3661
4115
|
program.addCommand(limaCommand);
|
|
3662
4116
|
program.action(() => {
|
|
3663
4117
|
console.log();
|
|
3664
|
-
console.log(` ${
|
|
3665
|
-
console.log(` ${
|
|
4118
|
+
console.log(` ${logger16.brand("RAPID")} ${logger16.dim(`v${VERSION}`)}`);
|
|
4119
|
+
console.log(` ${logger16.dim("AI-assisted development with dev containers")}`);
|
|
3666
4120
|
console.log();
|
|
3667
4121
|
program.help();
|
|
3668
4122
|
});
|
|
@@ -3670,4 +4124,4 @@ program.action(() => {
|
|
|
3670
4124
|
export {
|
|
3671
4125
|
program
|
|
3672
4126
|
};
|
|
3673
|
-
//# sourceMappingURL=chunk-
|
|
4127
|
+
//# sourceMappingURL=chunk-COGUXZI3.js.map
|