bx-mac 0.11.0 โ†’ 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +31 -18
  2. package/dist/bx.js +97 -30
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -17,7 +17,7 @@ AI-powered coding tools like Claude Code, Copilot, or Cline run with **broad fil
17
17
  bx ~/work/my-project
18
18
  ```
19
19
 
20
- That's it. ๐ŸŽ‰ VSCode opens with full access to `~/work/my-project` and nothing else.
20
+ That's it. ๐ŸŽ‰ VSCode opens with full access to `~/work/my-project` and nothing else. Read [the blog post](https://holtwick.de/blog/bx-sandbox) for more background on the motivation behind bx.
21
21
 
22
22
  Need multiple directories? No problem:
23
23
 
@@ -30,6 +30,7 @@ bx ~/work/my-project ~/work/shared-lib
30
30
  - ๐Ÿ”’ Blocks `~/Documents`, `~/Desktop`, `~/Downloads`, and all other personal folders
31
31
  - ๐Ÿšง Blocks sibling projects โ€” only the directory you specify is accessible
32
32
  - ๐Ÿ›ก๏ธ Protects sensitive dotdirs like `~/.ssh`, `~/.gnupg`, `~/.docker`, `~/.cargo`
33
+ - ๐Ÿ›๏ธ Opinionated protection for `~/Library` โ€” blocks privacy-sensitive subdirectories (Mail, Messages, Photos, Safari, Contacts, โ€ฆ) and containers of password managers/finance apps, while keeping tooling-relevant paths accessible
33
34
  - โš™๏ธ Keeps VSCode, extensions, shell, Node.js, and other tooling fully functional
34
35
  - ๐Ÿ” Generates sandbox rules dynamically based on your actual `$HOME` contents
35
36
  - ๐Ÿ“ Supports `.bxignore` files (searched recursively) to hide secrets like `.env` files within a project
@@ -81,7 +82,7 @@ For app modes, values before `--` define the sandbox scope (`workdir...`). Value
81
82
 
82
83
  For `xcode`, this distinction is important: the sandbox workdir is **not** passed as an Xcode open argument. Use `--` if you want to open a specific `.xcworkspace` or `.xcodeproj`.
83
84
 
84
- This behavior is configurable per app via `passWorkdirs` in `~/.bxconfig.toml` (default: `true`, built-in `xcode` default: `false`).
85
+ This behavior is configurable per app via `passPaths` in `~/.bxconfig.toml` (default: `true`, built-in `xcode` default: `false`).
85
86
 
86
87
  GUI app modes are activated in the foreground on launch (best effort), so the opened app should become the frontmost app.
87
88
 
@@ -113,6 +114,9 @@ bx zed ~/work/my-project
113
114
  # โšก Run a script in a sandbox
114
115
  bx exec ~/work/my-project -- python train.py
115
116
 
117
+ # ๐Ÿ”€ Run in the background (terminal stays free)
118
+ bx --background code ~/work/my-project
119
+
116
120
  # ๐Ÿ” Preview what will be protected (no launch)
117
121
  bx --dry ~/work/my-project
118
122
 
@@ -126,6 +130,7 @@ bx --verbose ~/work/my-project
126
130
  | --- | --- |
127
131
  | `--dry` | Show a tree of all protected, read-only, and accessible paths โ€” don't launch anything |
128
132
  | `--verbose` | Print the generated sandbox profile plus launch details (binary, arguments, cwd, focus command) |
133
+ | `--background` | Run the app detached in the background (like `nohup &`), output goes to `/tmp/bx-<pid>.log` |
129
134
  | `--profile-sandbox` | Use an isolated VSCode profile (separate extensions/settings, `code` mode only) |
130
135
 
131
136
  On normal runs, bx also prints a short policy summary (number of workdirs, blocked directories, hidden paths, and read-only directories).
@@ -154,43 +159,44 @@ path = "/usr/local/bin/code"
154
159
 
155
160
  | Field | Description |
156
161
  | --- | --- |
157
- | `mode` | Inherit from another app (e.g. `"code"`, `"cursor"`) โ€” only `workdirs` / overrides needed |
162
+ | `mode` | Inherit from another app (e.g. `"code"`, `"cursor"`) โ€” only `paths` / overrides needed |
158
163
  | `bundle` | macOS bundle identifier โ€” used with `mdfind` to find the app automatically |
159
164
  | `binary` | Relative path to the executable inside the `.app` bundle |
160
165
  | `path` | Absolute path to the executable **or** `.app` bundle (highest priority, skips discovery) |
161
166
  | `fallback` | Absolute fallback path if `mdfind` discovery fails |
162
167
  | `args` | Extra arguments always passed to the app |
163
- | `passWorkdirs` | Whether `workdir...` is forwarded as app launch args (`true`/`false`) |
164
- | `workdirs` | Default working directories when none are given on the CLI (supports `~/` paths) |
168
+ | `passPaths` | Paths passed as app launch args (`true`/`false`/`N`/`["~/p1", "~/p2"]`) |
169
+ | `paths` | Default working directories when none are given on the CLI (supports `~/` paths) |
170
+ | `background` | Run the app detached in the background by default (`true`/`false`) |
165
171
 
166
172
  **Resolution order:** `path` โ†’ `mdfind` by `bundle` + `binary` โ†’ `fallback`
167
173
 
168
- `passWorkdirs` controls launch argument behavior and is independent of sandbox scope. Even with `passWorkdirs = false`, the provided `workdir...` still defines what the sandbox can access.
174
+ `passPaths` controls launch argument behavior and is independent of sandbox scope. Even with `passPaths = false`, the provided `workdir...` still defines what the sandbox can access. Use `passPaths = 1` to pass only the first path as a launch argument, or `passPaths = ["~/specific/path"]` to pass explicit paths instead of workdirs.
169
175
 
170
- **Workdir shortcuts with `mode`** let you create named entries that inherit everything from an existing app โ€” just set `mode` and `workdirs`:
176
+ **Workdir shortcuts with `mode`** let you create named entries that inherit everything from an existing app โ€” just set `mode` and `paths`:
171
177
 
172
178
  ```toml
173
179
  # "bx myproject" opens VSCode with these directories
174
180
  [myproject]
175
181
  mode = "code"
176
- workdirs = ["~/work/my-project", "~/work/shared-lib"]
182
+ paths = ["~/work/my-project", "~/work/shared-lib"]
177
183
 
178
184
  # "bx ios" opens Xcode with this directory
179
185
  [ios]
180
186
  mode = "xcode"
181
- workdirs = ["~/work/my-ios-app"]
187
+ paths = ["~/work/my-ios-app"]
182
188
  ```
183
189
 
184
190
  Running `bx myproject` inherits VSCode's bundle, binary, args, and everything else โ€” no need to repeat the full app configuration. Own fields override inherited ones, so you can still customize specific settings. Chaining is supported (e.g. `myproject` โ†’ `cursor` โ†’ `code`).
185
191
 
186
- **Preconfigured workdirs** also work directly on app definitions:
192
+ **Preconfigured paths** also work directly on app definitions:
187
193
 
188
194
  ```toml
189
195
  [code]
190
- workdirs = ["~/work/my-project", "~/work/shared-lib"]
196
+ paths = ["~/work/my-project", "~/work/shared-lib"]
191
197
  ```
192
198
 
193
- Running `bx code` (without arguments) will then open VSCode with both directories sandboxed. CLI arguments always override configured workdirs.
199
+ Running `bx code` (without arguments) will then open VSCode with both directories sandboxed. CLI arguments always override configured paths.
194
200
 
195
201
  When overriding a built-in app, only the specified fields are replaced โ€” unset fields keep their defaults. See [`bxconfig.example.toml`](bxconfig.example.toml) for a complete reference.
196
202
 
@@ -216,9 +222,11 @@ ro:reference/docs
216
222
  ro:shared/toolchain
217
223
  ```
218
224
 
219
- Deny rules are applied **in addition** to the built-in protected list:
225
+ Deny rules are applied **in addition** to the built-in protected lists:
220
226
 
221
- > ๐Ÿ”’ `.ssh` `.gnupg` `.docker` `.zsh_sessions` `.cargo` `.gradle` `.gem`
227
+ > ๐Ÿ”’ **Dotdirs:** `.ssh` `.gnupg` `.docker` `.zsh_sessions` `.cargo` `.gradle` `.gem`
228
+ >
229
+ > ๐Ÿ›๏ธ **Library (opinionated):** `Accounts` `Calendars` `Contacts` `Cookies` `Finance` `Mail` `Messages` `Mobile Documents` `Photos` `Safari` and [others (see full list)](src/profile.ts) โ€” plus containers of password managers & finance apps
222
230
 
223
231
  ### `<project>/.bxignore`
224
232
 
@@ -288,9 +296,10 @@ bx generates a macOS sandbox profile at launch time:
288
296
  2. **Block** each one individually with `(deny file* (subpath ...))`
289
297
  3. **Skip** all working directories, `~/Library`, dotfiles, and `rw:`/`ro:` paths from `~/.bxignore`
290
298
  4. **Descend** into parent directories of allowed paths to block only siblings (because SBPL deny rules always override allow rules)
291
- 5. **Append** deny rules for protected dotdirs, plain entries in `~/.bxignore`, and `.bxignore` files found recursively in each working directory
292
- 6. **Apply** `(deny file-write*)` rules for `ro:` directories (read allowed, write blocked)
293
- 7. **Write** the profile to `/tmp`, launch the app via `sandbox-exec`, clean up on exit
299
+ 5. **Protect** an opinionated set of `~/Library` subdirectories (Mail, Messages, Photos, Safari, Contacts, Calendars, โ€ฆ) and app containers matching known password managers and finance apps (1Password, Bitwarden, MoneyMoney, โ€ฆ)
300
+ 6. **Append** deny rules for protected dotdirs, plain entries in `~/.bxignore`, and `.bxignore` files found recursively in each working directory
301
+ 7. **Apply** `(deny file-write*)` rules for `ro:` directories (read allowed, write blocked)
302
+ 8. **Write** the profile to `/tmp`, launch the app via `sandbox-exec`, clean up on exit
294
303
 
295
304
  ### Why not a simple deny-all + allow?
296
305
 
@@ -330,7 +339,7 @@ Or preconfigure them in `~/.bxconfig.toml`:
330
339
 
331
340
  ```toml
332
341
  [code]
333
- workdirs = ["~/work/project-a", "~/work/project-b"]
342
+ paths = ["~/work/project-a", "~/work/project-b"]
334
343
  ```
335
344
 
336
345
  For VSCode specifically, `--profile-sandbox` forces a separate Electron process via an isolated `--user-data-dir`, but this means separate extensions and settings.
@@ -363,6 +372,10 @@ Some AI coding tools ship with their own sandboxing. bx complements these by pro
363
372
 
364
373
  These are great when available, but they only protect within their own tool. bx wraps the entire process โ€” so even if a tool's built-in sandbox is misconfigured, disabled, or absent, your files stay protected.
365
374
 
375
+ ## ๐Ÿ”— Alternatives
376
+
377
+ - [Agent Safehouse](https://agent-safehouse.dev/) โ€” macOS kernel-level sandboxing for LLM coding agents via `sandbox-exec`. Deny-first model that blocks write access outside the project directory.
378
+
366
379
  ## ๐Ÿ“„ License
367
380
 
368
381
  MIT โ€” see [LICENSE](LICENSE).
package/dist/bx.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { accessSync, constants, cpSync, existsSync, globSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
2
+ import { accessSync, constants, cpSync, existsSync, globSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { basename, dirname, join, resolve } from "node:path";
4
4
  import { execFileSync, spawn } from "node:child_process";
5
5
  import { createInterface } from "node:readline";
@@ -797,7 +797,7 @@ const BUILTIN_APPS = {
797
797
  bundle: "com.apple.dt.Xcode",
798
798
  binary: "Contents/MacOS/Xcode",
799
799
  fallback: "/Applications/Xcode.app/Contents/MacOS/Xcode",
800
- passWorkdirs: false
800
+ passPaths: false
801
801
  }
802
802
  };
803
803
  /** Shell-only built-in modes that are not app definitions */
@@ -806,6 +806,20 @@ const BUILTIN_MODES = [
806
806
  "claude",
807
807
  "exec"
808
808
  ];
809
+ function parsePassPaths(val) {
810
+ if (typeof val === "boolean") return val;
811
+ if (typeof val === "number" && Number.isInteger(val) && val > 0) return val;
812
+ if (Array.isArray(val)) {
813
+ const paths = val.filter((a) => typeof a === "string");
814
+ if (paths.length > 0) return paths;
815
+ }
816
+ }
817
+ function parseStringArray(val) {
818
+ if (Array.isArray(val)) {
819
+ const items = val.filter((a) => typeof a === "string");
820
+ if (items.length > 0) return items;
821
+ }
822
+ }
809
823
  function parseAppDef(def) {
810
824
  return {
811
825
  mode: typeof def.mode === "string" ? def.mode : void 0,
@@ -813,9 +827,10 @@ function parseAppDef(def) {
813
827
  binary: typeof def.binary === "string" ? def.binary : void 0,
814
828
  path: typeof def.path === "string" ? def.path : void 0,
815
829
  fallback: typeof def.fallback === "string" ? def.fallback : void 0,
816
- args: Array.isArray(def.args) ? def.args.filter((a) => typeof a === "string") : void 0,
817
- passWorkdirs: typeof def.passWorkdirs === "boolean" ? def.passWorkdirs : void 0,
818
- workdirs: Array.isArray(def.workdirs) ? def.workdirs.filter((a) => typeof a === "string") : void 0
830
+ args: parseStringArray(def.args),
831
+ passPaths: parsePassPaths(def.passPaths ?? def.passWorkPaths ?? def.passWorkdirs),
832
+ paths: parseStringArray(def.paths ?? def.workdirs),
833
+ background: typeof def.background === "boolean" ? def.background : void 0
819
834
  };
820
835
  }
821
836
  /**
@@ -835,8 +850,12 @@ function loadConfig(home) {
835
850
  "path",
836
851
  "fallback",
837
852
  "args",
853
+ "passPaths",
854
+ "passWorkPaths",
838
855
  "passWorkdirs",
839
- "workdirs"
856
+ "paths",
857
+ "workdirs",
858
+ "background"
840
859
  ]);
841
860
  for (const [key, val] of Object.entries(doc)) {
842
861
  if (key === "apps") continue;
@@ -1032,14 +1051,6 @@ const ACCESS_PREFIX_RE = /^(RW|RO):(.+)$/i;
1032
1051
  function parseHomeConfig(home, workDirs) {
1033
1052
  const allowed = new Set(workDirs);
1034
1053
  const readOnly = /* @__PURE__ */ new Set();
1035
- const bxallowPath = join(home, ".bxallow");
1036
- if (existsSync(bxallowPath)) {
1037
- console.error("sandbox: WARNING โ€” ~/.bxallow is deprecated. Move entries to ~/.bxignore with RW: prefix.");
1038
- for (const line of parseLines(bxallowPath)) {
1039
- const absolute = resolve(home, line);
1040
- if (existsSync(absolute) && statSync(absolute).isDirectory()) allowed.add(absolute);
1041
- }
1042
- }
1043
1054
  for (const line of parseLines(join(home, ".bxignore"))) {
1044
1055
  const match = line.match(ACCESS_PREFIX_RE);
1045
1056
  if (!match) continue;
@@ -1265,6 +1276,7 @@ function parseArgs(validModes) {
1265
1276
  const verbose = rawArgs.includes("--verbose");
1266
1277
  const dry = rawArgs.includes("--dry");
1267
1278
  const profileSandbox = rawArgs.includes("--profile-sandbox");
1279
+ const background = rawArgs.includes("--background");
1268
1280
  const positional = rawArgs.filter((a) => !a.startsWith("--"));
1269
1281
  const doubleDashIdx = rawArgs.indexOf("--");
1270
1282
  const appArgs = doubleDashIdx >= 0 ? rawArgs.slice(doubleDashIdx + 1) : [];
@@ -1291,6 +1303,7 @@ function parseArgs(validModes) {
1291
1303
  verbose,
1292
1304
  dry,
1293
1305
  profileSandbox,
1306
+ background,
1294
1307
  appArgs,
1295
1308
  implicit: implicitWorkdirs
1296
1309
  };
@@ -1300,8 +1313,12 @@ function parseArgs(validModes) {
1300
1313
  function isBuiltinMode(mode) {
1301
1314
  return BUILTIN_MODES.includes(mode);
1302
1315
  }
1303
- function shouldPassWorkdirs(app) {
1304
- return app.passWorkdirs !== false;
1316
+ function getPassPaths(app, workDirs, home) {
1317
+ const val = app.passPaths;
1318
+ if (val === false) return [];
1319
+ if (typeof val === "number") return workDirs.slice(0, val);
1320
+ if (Array.isArray(val)) return val.map((p) => p.replace(/^~\//, home + "/"));
1321
+ return workDirs;
1305
1322
  }
1306
1323
  function appBundleFromPath(path) {
1307
1324
  if (path.endsWith(".app")) return path;
@@ -1372,7 +1389,7 @@ function buildAppCommand(mode, workDirs, home, profileSandbox, appArgs, apps) {
1372
1389
  }
1373
1390
  if (app.args) args.push(...app.args);
1374
1391
  if (appArgs.length > 0) args.push(...appArgs);
1375
- if (shouldPassWorkdirs(app)) args.push(...workDirs);
1392
+ args.push(...getPassPaths(app, workDirs, home));
1376
1393
  return {
1377
1394
  bin,
1378
1395
  args
@@ -1462,6 +1479,7 @@ const OPTIONS_TEXT = `
1462
1479
  Options:
1463
1480
  --dry show what will be protected, don't launch
1464
1481
  --verbose print the generated sandbox profile
1482
+ --background run in background, log output to /tmp/bx-<pid>.log
1465
1483
  --profile-sandbox use an isolated VSCode profile (code mode only)
1466
1484
  -v, --version show version
1467
1485
  -h, --help show this help
@@ -1474,7 +1492,8 @@ Configuration:
1474
1492
  binary = "..." relative path in .app bundle
1475
1493
  path = "..." explicit executable path
1476
1494
  args = ["..."] extra arguments
1477
- passWorkdirs = true|false pass workdirs as launch args
1495
+ passPaths = true|false|N|[...] paths passed as launch args
1496
+ background = true run in background by default
1478
1497
  built-in apps (code, xcode) can be overridden
1479
1498
  ~/.bxignore sandbox rules (one per line):
1480
1499
  path block access (deny)
@@ -1555,7 +1574,7 @@ function printDryRunTree({ home, blockedDirs, ignoredPaths, readOnlyDirs, workDi
1555
1574
  }
1556
1575
  //#endregion
1557
1576
  //#region package.json
1558
- var version = "0.11.0";
1577
+ var version = "1.0.0";
1559
1578
  //#endregion
1560
1579
  //#region src/index.ts
1561
1580
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -1575,16 +1594,16 @@ if (!process$1.env.HOME) {
1575
1594
  const HOME = process$1.env.HOME;
1576
1595
  async function main() {
1577
1596
  const apps = getAvailableApps(loadConfig(HOME));
1578
- const { mode, workArgs, verbose, dry, profileSandbox, appArgs, implicit } = parseArgs(getValidModes(apps));
1597
+ const { mode, workArgs, verbose, dry, profileSandbox, background: backgroundFlag, appArgs, implicit } = parseArgs(getValidModes(apps));
1579
1598
  const app = apps[mode];
1580
- const workDirs = (implicit && app?.workdirs?.length ? app.workdirs : workArgs).map((a) => resolve(a.replace(/^~\//, HOME + "/")));
1581
- if (implicit && !app?.workdirs?.length) {
1599
+ const workDirs = (implicit && app?.paths?.length ? app.paths : workArgs).map((a) => realpathSync(resolve(a.replace(/^~\//, HOME + "/"))));
1600
+ if (implicit && !app?.paths?.length) {
1582
1601
  if (workDirs.some((d) => d === HOME)) {
1583
1602
  console.error(`\n${fmt.error("no working directory specified and current directory is $HOME")}\n`);
1584
1603
  console.error(fmt.detail(`Usage: bx ${mode} <workdir>`));
1585
- console.error(fmt.detail(`Config: set default workdirs in ~/.bxconfig.toml:\n`));
1604
+ console.error(fmt.detail(`Config: set default paths in ~/.bxconfig.toml:\n`));
1586
1605
  console.error(fmt.detail(`[${mode}]`));
1587
- console.error(fmt.detail(`workdirs = ["~/work/my-project"]\n`));
1606
+ console.error(fmt.detail(`paths = ["~/work/my-project"]\n`));
1588
1607
  process$1.exit(1);
1589
1608
  }
1590
1609
  if (!dry) await confirmLaunch(workDirs[0], mode);
@@ -1618,13 +1637,54 @@ async function main() {
1618
1637
  });
1619
1638
  process$1.exit(0);
1620
1639
  }
1621
- const profilePath = join("/tmp", `bx-${process$1.pid}.sb`);
1622
- writeFileSync(profilePath, profile);
1640
+ const tmpDir = mkdtempSync(join("/tmp", "bx-"));
1641
+ const profilePath = join(tmpDir, "profile.sb");
1642
+ writeFileSync(profilePath, profile, { mode: 384 });
1623
1643
  const cmd = buildCommand(mode, workDirs, HOME, profileSandbox, appArgs, apps);
1644
+ const background = backgroundFlag || app?.background === true;
1624
1645
  const nestedSandboxWarning = getNestedSandboxWarning(mode, apps);
1625
1646
  if (nestedSandboxWarning) console.error(fmt.detail(nestedSandboxWarning));
1626
- if (verbose) printLaunchDetails(cmd, workDirs[0], getActivationCommand(mode, apps));
1647
+ printLaunchDetails(cmd, workDirs[0]);
1648
+ if (verbose) {
1649
+ const activationCmd = getActivationCommand(mode, apps);
1650
+ if (activationCmd) {
1651
+ const quote = (a) => JSON.stringify(a);
1652
+ console.error(fmt.detail(`focus: ${activationCmd.bin} ${activationCmd.args.map(quote).join(" ")}`));
1653
+ }
1654
+ }
1627
1655
  console.error("");
1656
+ if (background) {
1657
+ const logPath = join(tmpDir, "bx.log");
1658
+ const logFd = openSync(logPath, "a", 384);
1659
+ const child = spawn("sandbox-exec", [
1660
+ "-f",
1661
+ profilePath,
1662
+ "-D",
1663
+ `HOME=${HOME}`,
1664
+ "-D",
1665
+ `WORK=${workDirs[0]}`,
1666
+ cmd.bin,
1667
+ ...cmd.args
1668
+ ], {
1669
+ cwd: workDirs[0],
1670
+ stdio: [
1671
+ "ignore",
1672
+ logFd,
1673
+ logFd
1674
+ ],
1675
+ detached: true,
1676
+ env: {
1677
+ ...process$1.env,
1678
+ CODEBOX_SANDBOX: "1"
1679
+ }
1680
+ });
1681
+ child.unref();
1682
+ bringAppToFront(mode, apps);
1683
+ console.error(fmt.info(`running in background (pid ${child.pid})`));
1684
+ console.error(fmt.detail(`log: ${logPath}`));
1685
+ console.error(fmt.detail(`sandbox profile: ${profilePath} (kept until process exits)`));
1686
+ process$1.exit(0);
1687
+ }
1628
1688
  const child = spawn("sandbox-exec", [
1629
1689
  "-f",
1630
1690
  profilePath,
@@ -1643,8 +1703,16 @@ async function main() {
1643
1703
  }
1644
1704
  });
1645
1705
  bringAppToFront(mode, apps);
1706
+ const cleanup = () => {
1707
+ try {
1708
+ rmSync(tmpDir, {
1709
+ recursive: true,
1710
+ force: true
1711
+ });
1712
+ } catch {}
1713
+ };
1714
+ process$1.on("exit", cleanup);
1646
1715
  child.on("close", (code) => {
1647
- rmSync(profilePath, { force: true });
1648
1716
  process$1.exit(code ?? 0);
1649
1717
  });
1650
1718
  }
@@ -1668,12 +1736,11 @@ function printPolicySummary(mode, workDirs, blockedDirs, ignoredPaths, readOnly)
1668
1736
  if (extraIgnored > 0) parts.push(`${extraIgnored} from .bxignore`);
1669
1737
  console.error(fmt.detail(parts.join(" ยท ")));
1670
1738
  }
1671
- function printLaunchDetails(cmd, cwd, activationCmd) {
1739
+ function printLaunchDetails(cmd, cwd) {
1672
1740
  const quote = (a) => JSON.stringify(a);
1673
1741
  console.error(fmt.detail(`bin: ${cmd.bin}`));
1674
1742
  console.error(fmt.detail(`args: ${cmd.args.map(quote).join(" ") || "(none)"}`));
1675
1743
  console.error(fmt.detail(`cwd: ${cwd}`));
1676
- if (activationCmd) console.error(fmt.detail(`focus: ${activationCmd.bin} ${activationCmd.args.map(quote).join(" ")}`));
1677
1744
  }
1678
1745
  main();
1679
1746
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bx-mac",
3
- "version": "0.11.0",
3
+ "version": "1.0.0",
4
4
  "description": "Sandbox any macOS app โ€” only your project directory stays accessible",
5
5
  "type": "module",
6
6
  "bin": {