@a3t/rapid 0.1.11 → 0.1.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  program
4
- } from "./chunk-J7OOLQCF.js";
4
+ } from "./chunk-BLH6BAR5.js";
5
5
 
6
6
  // src/bin.ts
7
7
  program.parse(process.argv);
@@ -20,7 +20,8 @@ import {
20
20
  writeOpenCodeConfig,
21
21
  RAPID_METHODOLOGY,
22
22
  MCP_USAGE_GUIDELINES,
23
- GIT_GUIDELINES
23
+ GIT_GUIDELINES,
24
+ formatJson
24
25
  } from "@a3t/rapid-core";
25
26
  import ora from "ora";
26
27
  async function detectProjectType(dir) {
@@ -80,7 +81,11 @@ async function detectProjectType(dir) {
80
81
  }
81
82
  if (fileSet.has("package.json")) {
82
83
  const pkgManager = fileSet.has("pnpm-lock.yaml") ? "pnpm" : fileSet.has("yarn.lock") ? "yarn" : "npm";
83
- return { language: "javascript", packageManager: pkgManager, confidence: "medium" };
84
+ return {
85
+ language: "javascript",
86
+ packageManager: pkgManager,
87
+ confidence: "medium"
88
+ };
84
89
  }
85
90
  return { language: "unknown", confidence: "low" };
86
91
  }
@@ -465,7 +470,7 @@ async function createDevContainer(dir, detected, force = false, usePrebuilt = fa
465
470
  }
466
471
  await mkdir(devcontainerDir, { recursive: true });
467
472
  const config = getDevContainerConfig(detected, usePrebuilt);
468
- await writeFile(devcontainerJsonPath, JSON.stringify(config, null, 2) + "\n");
473
+ await writeFile(devcontainerJsonPath, await formatJson(config));
469
474
  return true;
470
475
  }
471
476
  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) => {
@@ -549,7 +554,7 @@ var initCommand = new Command("init").description("Initialize RAPID in a project
549
554
  }
550
555
  }
551
556
  spinner.text = "Writing rapid.json...";
552
- await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
557
+ await writeFile(configPath, await formatJson(config));
553
558
  if (mcpServers.length > 0) {
554
559
  spinner.text = "Generating MCP configuration files...";
555
560
  await writeMcpConfig(cwd, config);
@@ -763,7 +768,8 @@ import {
763
768
  hasVaultCli,
764
769
  isVaultAuthenticated,
765
770
  buildAgentArgs,
766
- agentSupportsRuntimeInjection
771
+ agentSupportsRuntimeInjection,
772
+ formatJson as formatJson2
767
773
  } from "@a3t/rapid-core";
768
774
  import ora2 from "ora";
769
775
 
@@ -991,7 +997,7 @@ async function cleanupMergedWorktrees(repoRoot) {
991
997
 
992
998
  // src/isolation/lima.ts
993
999
  import { execa as execa2 } from "execa";
994
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1000
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, access as access3 } from "fs/promises";
995
1001
  import { homedir, platform } from "os";
996
1002
  import { join as join3, dirname as dirname2 } from "path";
997
1003
  import { fileURLToPath } from "url";
@@ -1061,7 +1067,19 @@ async function getInstance(name = RAPID_LIMA_INSTANCE) {
1061
1067
  }
1062
1068
  async function instanceExists(name = RAPID_LIMA_INSTANCE) {
1063
1069
  const instance = await getInstance(name);
1064
- return instance !== null;
1070
+ if (instance !== null) {
1071
+ return true;
1072
+ }
1073
+ return instanceDirExists(name);
1074
+ }
1075
+ async function instanceDirExists(name = RAPID_LIMA_INSTANCE) {
1076
+ const instanceDir = join3(homedir(), ".lima", name);
1077
+ try {
1078
+ await access3(instanceDir);
1079
+ return true;
1080
+ } catch {
1081
+ return false;
1082
+ }
1065
1083
  }
1066
1084
  async function isRunning(name = RAPID_LIMA_INSTANCE) {
1067
1085
  const instance = await getInstance(name);
@@ -1105,6 +1123,10 @@ async function createLimaConfig(projectDir, options = {}) {
1105
1123
  ${envLines}
1106
1124
  `);
1107
1125
  }
1126
+ if (options.installGh === false) {
1127
+ 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/;
1128
+ config = config.replace(ghInstallPattern, "\n");
1129
+ }
1108
1130
  await writeFile2(configPath, config);
1109
1131
  return configPath;
1110
1132
  }
@@ -1182,7 +1204,9 @@ async function startInstance(projectDir, options = {}) {
1182
1204
  return { success: true };
1183
1205
  }
1184
1206
  await execa2("limactl", ["start", name], {
1185
- timeout: (options.timeout ?? 300) * 1e3
1207
+ timeout: (options.timeout ?? 300) * 1e3,
1208
+ stdio: "inherit"
1209
+ // Show progress
1186
1210
  });
1187
1211
  } else {
1188
1212
  const configPath = await createLimaConfig(projectDir, options);
@@ -1284,6 +1308,56 @@ async function shellInLima(options = {}) {
1284
1308
  }
1285
1309
  await execa2("limactl", args, { stdio: "inherit" });
1286
1310
  }
1311
+ var AGENT_INSTALL_COMMANDS = {
1312
+ claude: ["sudo", "npm", "install", "-g", "@anthropic-ai/claude-code"],
1313
+ opencode: ["bash", "-c", "curl -fsSL https://opencode.ai/install | bash"],
1314
+ aider: ["pip3", "install", "--user", "aider-chat"]
1315
+ };
1316
+ async function isAgentInstalled(agentCli, name = RAPID_LIMA_INSTANCE) {
1317
+ try {
1318
+ const result = await execInLima(["which", agentCli], { name });
1319
+ return result.success && !!result.stdout?.trim();
1320
+ } catch {
1321
+ return false;
1322
+ }
1323
+ }
1324
+ async function installAgent(agentCli, name = RAPID_LIMA_INSTANCE) {
1325
+ const installCmd = AGENT_INSTALL_COMMANDS[agentCli];
1326
+ if (!installCmd) {
1327
+ return {
1328
+ success: false,
1329
+ error: `Unknown agent "${agentCli}". No install command available.`
1330
+ };
1331
+ }
1332
+ try {
1333
+ const result = await execInLima(installCmd, { name });
1334
+ if (!result.success) {
1335
+ return {
1336
+ success: false,
1337
+ error: result.error || result.stderr || `Failed to install ${agentCli}`
1338
+ };
1339
+ }
1340
+ const installed = await isAgentInstalled(agentCli, name);
1341
+ if (!installed) {
1342
+ return {
1343
+ success: false,
1344
+ error: `Installation command succeeded but ${agentCli} is not in PATH`
1345
+ };
1346
+ }
1347
+ return { success: true };
1348
+ } catch (err) {
1349
+ return {
1350
+ success: false,
1351
+ error: err instanceof Error ? err.message : String(err)
1352
+ };
1353
+ }
1354
+ }
1355
+ async function ensureAgentInstalled(agentCli, name = RAPID_LIMA_INSTANCE) {
1356
+ if (await isAgentInstalled(agentCli, name)) {
1357
+ return { success: true };
1358
+ }
1359
+ return installAgent(agentCli, name);
1360
+ }
1287
1361
  async function setupGitSsh(name = RAPID_LIMA_INSTANCE) {
1288
1362
  try {
1289
1363
  const result = await execInLima(["ssh-add", "-l"], { name });
@@ -1482,22 +1556,22 @@ async function prepareMcpEnv(rootDir, mcp) {
1482
1556
  }
1483
1557
  const configFile = mcp.configFile ?? ".mcp.json";
1484
1558
  const configPath = isAbsolute(configFile) ? configFile : join4(rootDir, configFile);
1485
- const servers = {};
1559
+ const mcpServers = {};
1486
1560
  for (const [name, serverConfig] of Object.entries(mcp.servers)) {
1487
1561
  if (!serverConfig || typeof serverConfig !== "object") {
1488
1562
  continue;
1489
1563
  }
1490
- const { enabled, ...rest } = serverConfig;
1564
+ const { enabled, type, ...rest } = serverConfig;
1491
1565
  if (enabled === false) {
1492
1566
  continue;
1493
1567
  }
1494
- servers[name] = rest;
1568
+ const outputType = type === "remote" ? "http" : type;
1569
+ mcpServers[name] = { type: outputType, ...rest };
1495
1570
  }
1496
- if (Object.keys(servers).length === 0) {
1571
+ if (Object.keys(mcpServers).length === 0) {
1497
1572
  return void 0;
1498
1573
  }
1499
- await writeFile3(configPath, `${JSON.stringify({ servers }, null, 2)}
1500
- `, "utf-8");
1574
+ await writeFile3(configPath, await formatJson2({ mcpServers }), "utf-8");
1501
1575
  return {
1502
1576
  MCP_CONFIG_FILE: configFile
1503
1577
  };
@@ -1578,7 +1652,7 @@ async function runLocally(agent, agentName, rootDir, config) {
1578
1652
  const mergedEnv = { ...secrets, ...mcpEnv ?? {} };
1579
1653
  const builtArgs = buildAgentArgs(agent, { injectSystemPrompt: true });
1580
1654
  if (isMacOS() && await hasLima()) {
1581
- await runInLimaVm(agent, agentName, rootDir, builtArgs, mergedEnv);
1655
+ await runInLimaVm(agent, agentName, rootDir, builtArgs, mergedEnv, config.lima);
1582
1656
  return;
1583
1657
  }
1584
1658
  logger2.info(`Launching ${logger2.brand(agentName)}...`);
@@ -1596,14 +1670,15 @@ async function runLocally(agent, agentName, rootDir, config) {
1596
1670
  }
1597
1671
  });
1598
1672
  }
1599
- async function runInLimaVm(agent, agentName, rootDir, args, env) {
1673
+ async function runInLimaVm(agent, agentName, rootDir, args, env, limaConfig) {
1600
1674
  const spinner = ora2();
1601
1675
  if (!await isRunning()) {
1602
1676
  spinner.start(`Starting Lima VM (${RAPID_LIMA_INSTANCE})...`);
1603
1677
  const result = await startInstance(rootDir, {
1604
1678
  env,
1605
- timeout: 600
1679
+ timeout: 600,
1606
1680
  // 10 minutes for first-time setup
1681
+ ...limaConfig?.installGh !== void 0 && { installGh: limaConfig.installGh }
1607
1682
  });
1608
1683
  if (!result.success) {
1609
1684
  spinner.fail("Failed to start Lima VM");
@@ -1626,6 +1701,26 @@ async function runInLimaVm(agent, agentName, rootDir, args, env) {
1626
1701
  } else {
1627
1702
  logger2.info(`Lima VM (${RAPID_LIMA_INSTANCE}) is running`);
1628
1703
  }
1704
+ spinner.start(`Checking if ${agentName} is installed in Lima VM...`);
1705
+ const installResult = await ensureAgentInstalled(agent.cli);
1706
+ if (!installResult.success) {
1707
+ spinner.fail(`Failed to install ${agentName} in Lima VM`);
1708
+ logger2.error(installResult.error ?? "Unknown error");
1709
+ logger2.blank();
1710
+ logger2.info("Falling back to running directly on host...");
1711
+ logger2.blank();
1712
+ const { execa: execa4 } = await import("execa");
1713
+ await execa4(agent.cli, args, {
1714
+ cwd: rootDir,
1715
+ stdio: "inherit",
1716
+ env: {
1717
+ ...process.env,
1718
+ ...env
1719
+ }
1720
+ });
1721
+ return;
1722
+ }
1723
+ spinner.succeed(`${agentName} is available in Lima VM`);
1629
1724
  logger2.info(`Launching ${logger2.brand(agentName)} in Lima VM...`);
1630
1725
  logger2.dim(`Working directory: ${rootDir}`);
1631
1726
  logger2.dim("SSH agent forwarded for commit signing");
@@ -1952,7 +2047,7 @@ var statusCommand = new Command3("status").description("Show environment status"
1952
2047
  // src/commands/agent.ts
1953
2048
  import { writeFile as writeFile4 } from "fs/promises";
1954
2049
  import { Command as Command4 } from "commander";
1955
- import { loadConfig as loadConfig3, checkAllAgents as checkAllAgents2, logger as logger4 } from "@a3t/rapid-core";
2050
+ import { loadConfig as loadConfig3, checkAllAgents as checkAllAgents2, logger as logger4, formatJson as formatJson3 } from "@a3t/rapid-core";
1956
2051
  var agentCommand = new Command4("agent").description("Manage AI agents");
1957
2052
  agentCommand.command("list").description("List available agents").action(async () => {
1958
2053
  try {
@@ -2006,13 +2101,49 @@ agentCommand.command("default [name]").description("Get or set default agent").a
2006
2101
  process.exit(1);
2007
2102
  }
2008
2103
  config.agents.default = name;
2009
- await writeFile4(loaded.filepath, JSON.stringify(config, null, 2) + "\n");
2104
+ await writeFile4(loaded.filepath, await formatJson3(config));
2010
2105
  logger4.success(`Default agent set to "${name}"`);
2011
2106
  } catch (error) {
2012
2107
  logger4.error(error instanceof Error ? error.message : String(error));
2013
2108
  process.exit(1);
2014
2109
  }
2015
2110
  });
2111
+ agentCommand.command("yolo [name]").description("Enable YOLO mode (skip all permission prompts) for an agent").option("--off", "Disable YOLO mode").action(async (name, options) => {
2112
+ try {
2113
+ const loaded = await loadConfig3();
2114
+ if (!loaded) {
2115
+ logger4.error("No rapid.json found. Run `rapid init` first.");
2116
+ process.exit(1);
2117
+ }
2118
+ const { config } = loaded;
2119
+ const agentName = name || config.agents.default;
2120
+ if (!config.agents.available[agentName]) {
2121
+ logger4.error(`Agent "${agentName}" not found in configuration`);
2122
+ logger4.info("Available agents:");
2123
+ Object.keys(config.agents.available).forEach((n) => {
2124
+ console.log(` - ${n}`);
2125
+ });
2126
+ process.exit(1);
2127
+ }
2128
+ const agent = config.agents.available[agentName];
2129
+ const enabling = !options.off;
2130
+ if (enabling && agent.cli !== "claude") {
2131
+ logger4.warn(`YOLO mode is only supported for Claude (${agentName} uses ${agent.cli})`);
2132
+ logger4.info("Continuing anyway...");
2133
+ }
2134
+ agent.yolo = enabling;
2135
+ await writeFile4(loaded.filepath, await formatJson3(config));
2136
+ if (enabling) {
2137
+ logger4.success(`YOLO mode enabled for "${agentName}"`);
2138
+ logger4.dim("Permission prompts will be skipped (--dangerously-skip-permissions)");
2139
+ } else {
2140
+ logger4.success(`YOLO mode disabled for "${agentName}"`);
2141
+ }
2142
+ } catch (error) {
2143
+ logger4.error(error instanceof Error ? error.message : String(error));
2144
+ process.exit(1);
2145
+ }
2146
+ });
2016
2147
 
2017
2148
  // src/commands/start.ts
2018
2149
  import { Command as Command5 } from "commander";
@@ -2701,7 +2832,8 @@ import {
2701
2832
  writeMcpConfig as writeMcpConfig2,
2702
2833
  writeOpenCodeConfig as writeOpenCodeConfig2,
2703
2834
  MCP_SERVER_TEMPLATES as MCP_SERVER_TEMPLATES2,
2704
- getMcpTemplate
2835
+ getMcpTemplate,
2836
+ formatJson as formatJson4
2705
2837
  } from "@a3t/rapid-core";
2706
2838
  import ora8 from "ora";
2707
2839
  var mcpCommand = new Command9("mcp").description(
@@ -2709,7 +2841,7 @@ var mcpCommand = new Command9("mcp").description(
2709
2841
  );
2710
2842
  async function saveConfig(rootDir, config) {
2711
2843
  const configPath = join5(rootDir, "rapid.json");
2712
- await writeFile5(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
2844
+ await writeFile5(configPath, await formatJson4(config), "utf-8");
2713
2845
  }
2714
2846
  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) => {
2715
2847
  try {
@@ -3619,4 +3751,4 @@ program.action(() => {
3619
3751
  export {
3620
3752
  program
3621
3753
  };
3622
- //# sourceMappingURL=chunk-J7OOLQCF.js.map
3754
+ //# sourceMappingURL=chunk-BLH6BAR5.js.map