yolobox 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +101 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -247,6 +247,17 @@ function execInContainer(id, command) {
247
247
  log(`Exec exited with code ${result.status}`);
248
248
  return result.status ?? 1;
249
249
  }
250
+ function execInContainerNonInteractive(id, command) {
251
+ const args = ["exec", `yolobox-${id}`, ...command];
252
+ log(`Exec (non-interactive) in container: docker ${args.join(" ")}`);
253
+ const result = spawnSync("docker", args, { stdio: ["pipe", "pipe", "pipe"] });
254
+ logCommand("docker", args, {
255
+ status: result.status,
256
+ stdout: result.stdout?.toString() || "",
257
+ stderr: result.stderr?.toString() || ""
258
+ });
259
+ return result.status === 0;
260
+ }
250
261
  function timeAgo(dateStr) {
251
262
  const date = new Date(dateStr);
252
263
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
@@ -317,7 +328,7 @@ function killContainer(id) {
317
328
  import * as p from "@clack/prompts";
318
329
  import pc2 from "picocolors";
319
330
  function intro2() {
320
- p.intro(pc2.bgCyan(pc2.black(` yolobox v${"0.1.5"} `)));
331
+ p.intro(pc2.bgCyan(pc2.black(` yolobox v${"0.1.6"} `)));
321
332
  }
322
333
  function success(message) {
323
334
  p.log.success(message);
@@ -569,10 +580,11 @@ function showStatus() {
569
580
  import { defineCommand as defineCommand3 } from "citty";
570
581
 
571
582
  // src/lib/container-setup.ts
583
+ import fs2 from "fs";
572
584
  import path2 from "path";
573
585
 
574
586
  // src/lib/git.ts
575
- import { execSync as execSync2 } from "child_process";
587
+ import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
576
588
  function exec(cmd) {
577
589
  return execSync2(cmd, {
578
590
  encoding: "utf-8",
@@ -637,6 +649,28 @@ function getGitIdentity() {
637
649
  return { name: "", email: "" };
638
650
  }
639
651
  }
652
+ function listUntrackedFiles(repoRoot, pathspec) {
653
+ const result = spawnSync2(
654
+ "git",
655
+ [
656
+ "-C",
657
+ repoRoot,
658
+ "ls-files",
659
+ "--others",
660
+ "--exclude-standard",
661
+ "--",
662
+ pathspec
663
+ ],
664
+ {
665
+ encoding: "utf-8",
666
+ stdio: ["pipe", "pipe", "pipe"]
667
+ }
668
+ );
669
+ if (result.status !== 0) return [];
670
+ const output = result.stdout?.trim() ?? "";
671
+ if (!output) return [];
672
+ return output.split("\n").filter(Boolean);
673
+ }
640
674
 
641
675
  // src/lib/id.ts
642
676
  var ADJECTIVES = [
@@ -1408,6 +1442,44 @@ function getExistingWorktreeIds(repoRoot) {
1408
1442
  }
1409
1443
 
1410
1444
  // src/lib/container-setup.ts
1445
+ function copyUntrackedFilesFromCwd(options) {
1446
+ const { repoRoot, worktreePath, cwd } = options;
1447
+ const relativeCwd = path2.relative(repoRoot, cwd);
1448
+ if (relativeCwd.startsWith("..") || path2.isAbsolute(relativeCwd)) {
1449
+ log(`Skipping untracked copy: cwd outside repo (${cwd})`);
1450
+ return 0;
1451
+ }
1452
+ if (relativeCwd.split(path2.sep).includes(".yolobox")) {
1453
+ log(`Skipping untracked copy: cwd inside .yolobox (${cwd})`);
1454
+ return 0;
1455
+ }
1456
+ const pathspec = relativeCwd === "" ? "." : relativeCwd;
1457
+ const files = listUntrackedFiles(repoRoot, pathspec);
1458
+ if (files.length === 0) return 0;
1459
+ let copied = 0;
1460
+ for (const file of files) {
1461
+ const src = path2.join(repoRoot, file);
1462
+ const dest = path2.join(worktreePath, file);
1463
+ try {
1464
+ if (fs2.existsSync(dest)) continue;
1465
+ fs2.mkdirSync(path2.dirname(dest), { recursive: true });
1466
+ const stat = fs2.lstatSync(src);
1467
+ if (stat.isSymbolicLink()) {
1468
+ const target = fs2.readlinkSync(src);
1469
+ fs2.symlinkSync(target, dest);
1470
+ } else if (stat.isDirectory()) {
1471
+ fs2.mkdirSync(dest, { recursive: true });
1472
+ } else {
1473
+ fs2.copyFileSync(src, dest);
1474
+ }
1475
+ copied++;
1476
+ } catch (err) {
1477
+ const message = err instanceof Error ? err.message : String(err);
1478
+ log(`Failed to copy untracked file "${file}": ${message}`);
1479
+ }
1480
+ }
1481
+ return copied;
1482
+ }
1411
1483
  async function setupContainer(options = {}) {
1412
1484
  intro2();
1413
1485
  if (isEnabled()) {
@@ -1471,6 +1543,18 @@ async function setupContainer(options = {}) {
1471
1543
  success(`Created worktree .yolobox/${id} (branch: yolo/${id})`);
1472
1544
  }
1473
1545
  ensureGitignore(repoRoot);
1546
+ if (!worktreeAlreadyExists && !branchAlreadyExists) {
1547
+ const copied = copyUntrackedFilesFromCwd({
1548
+ repoRoot,
1549
+ worktreePath,
1550
+ cwd: process.cwd()
1551
+ });
1552
+ if (copied > 0) {
1553
+ const cwdRel = path2.relative(repoRoot, process.cwd()) || ".";
1554
+ const label = copied === 1 ? "file" : "files";
1555
+ info(`Copied ${copied} untracked ${label} from ${cwdRel}`);
1556
+ }
1557
+ }
1474
1558
  const gitIdentity = getGitIdentity();
1475
1559
  log("Resolving Docker image...");
1476
1560
  const imageResolution = resolveDockerImage({
@@ -1546,6 +1630,17 @@ async function setupContainer(options = {}) {
1546
1630
  }
1547
1631
  process.exit(1);
1548
1632
  }
1633
+ const safeDirOk = execInContainerNonInteractive(id, [
1634
+ "git",
1635
+ "config",
1636
+ "--global",
1637
+ "--add",
1638
+ "safe.directory",
1639
+ "/workspace"
1640
+ ]);
1641
+ if (!safeDirOk) {
1642
+ log("Failed to mark /workspace as a safe git directory");
1643
+ }
1549
1644
  return { id, repoRoot };
1550
1645
  }
1551
1646
 
@@ -1578,7 +1673,7 @@ var claude_default = defineCommand3({
1578
1673
  });
1579
1674
 
1580
1675
  // src/commands/help.ts
1581
- import { spawnSync as spawnSync2 } from "child_process";
1676
+ import { spawnSync as spawnSync3 } from "child_process";
1582
1677
  import { defineCommand as defineCommand4 } from "citty";
1583
1678
  var help_default = defineCommand4({
1584
1679
  meta: {
@@ -1586,7 +1681,7 @@ var help_default = defineCommand4({
1586
1681
  description: "Show help information"
1587
1682
  },
1588
1683
  run: async () => {
1589
- const result = spawnSync2(process.argv[0], [process.argv[1], "--help"], {
1684
+ const result = spawnSync3(process.argv[0], [process.argv[1], "--help"], {
1590
1685
  stdio: "inherit"
1591
1686
  });
1592
1687
  process.exit(result.status || 0);
@@ -2023,7 +2118,7 @@ var debugIndex = process.argv.indexOf("--debug");
2023
2118
  if (debugIndex !== -1) {
2024
2119
  process.argv.splice(debugIndex, 1);
2025
2120
  const logPath = enable();
2026
- log(`yolobox v${"0.1.5"}`);
2121
+ log(`yolobox v${"0.1.6"}`);
2027
2122
  log(`args: ${process.argv.slice(2).join(" ")}`);
2028
2123
  log(`cwd: ${process.cwd()}`);
2029
2124
  log(`node: ${process.version}`);
@@ -2033,7 +2128,7 @@ if (debugIndex !== -1) {
2033
2128
  var main = defineCommand10({
2034
2129
  meta: {
2035
2130
  name: "yolobox",
2036
- version: "0.1.5",
2131
+ version: "0.1.6",
2037
2132
  description: "Run Claude Code in Docker containers. YOLO safely."
2038
2133
  },
2039
2134
  subCommands: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yolobox",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Run Claude Code in a Docker container with --dangerously-skip-permissions. YOLO safely.",
5
5
  "type": "module",
6
6
  "bin": {