clabox 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/clabox.config.example.mjs +90 -0
  4. package/docs/guideline.md +196 -0
  5. package/docs/logo.png +0 -0
  6. package/lib/aliases-DKGcMHHe.js +60 -0
  7. package/lib/aliases-DKGcMHHe.js.map +1 -0
  8. package/lib/aliases-DXyz-ufw.d.ts +31 -0
  9. package/lib/app-CieBa29D.js +246 -0
  10. package/lib/app-CieBa29D.js.map +1 -0
  11. package/lib/app-CpuMtOoj.d.ts +30 -0
  12. package/lib/cli.d.ts +1 -0
  13. package/lib/cli.js +71 -0
  14. package/lib/cli.js.map +1 -0
  15. package/lib/config-BQ44iVWT.js +155 -0
  16. package/lib/config-BQ44iVWT.js.map +1 -0
  17. package/lib/config-DQWueb4a.d.ts +134 -0
  18. package/lib/ghostty-Ca0g9P9P.js +74 -0
  19. package/lib/ghostty-Ca0g9P9P.js.map +1 -0
  20. package/lib/ghostty-DemKkfqf.d.ts +34 -0
  21. package/lib/index.d.ts +9 -0
  22. package/lib/index.js +9 -0
  23. package/lib/init/aliases.d.ts +2 -0
  24. package/lib/init/aliases.js +2 -0
  25. package/lib/init/app.d.ts +2 -0
  26. package/lib/init/app.js +2 -0
  27. package/lib/init/ghostty.d.ts +2 -0
  28. package/lib/init/ghostty.js +2 -0
  29. package/lib/init/raycast.d.ts +2 -0
  30. package/lib/init/raycast.js +2 -0
  31. package/lib/init/scaffold.d.ts +2 -0
  32. package/lib/init/scaffold.js +2 -0
  33. package/lib/profile-BeM41NXc.d.ts +29 -0
  34. package/lib/profile-DM6NAgb-.js +100 -0
  35. package/lib/profile-DM6NAgb-.js.map +1 -0
  36. package/lib/raycast-BCdO2Se1.js +35 -0
  37. package/lib/raycast-BCdO2Se1.js.map +1 -0
  38. package/lib/raycast-DM7c559f.d.ts +22 -0
  39. package/lib/run-CNehSQ-S.js +113 -0
  40. package/lib/run-CNehSQ-S.js.map +1 -0
  41. package/lib/run-Cx8cuTh5.d.ts +25 -0
  42. package/lib/sandbox/profile.d.ts +2 -0
  43. package/lib/sandbox/profile.js +2 -0
  44. package/lib/sandbox/run.d.ts +2 -0
  45. package/lib/sandbox/run.js +2 -0
  46. package/lib/scaffold-ByIbYAeS.d.ts +46 -0
  47. package/lib/scaffold-CRzC5KYe.js +141 -0
  48. package/lib/scaffold-CRzC5KYe.js.map +1 -0
  49. package/lib/utils/config.d.ts +2 -0
  50. package/lib/utils/config.js +2 -0
  51. package/package.json +141 -7
@@ -0,0 +1,113 @@
1
+ import { i as expandHome, t as HOME } from "./config-BQ44iVWT.js";
2
+ import { n as detectPackagePaths, t as buildProfile } from "./profile-DM6NAgb-.js";
3
+ import path from "node:path";
4
+ import { execFileSync, spawnSync } from "node:child_process";
5
+ import fs from "node:fs";
6
+ import crypto from "node:crypto";
7
+ //#region src/sandbox/run.ts
8
+ const TMPDIR = (process.env.TMPDIR || "/tmp").replace(/\/$/, "");
9
+ /** Deterministic per-project profile path under TMPDIR. */
10
+ function profilePath(projectDir = process.cwd()) {
11
+ const hash = crypto.createHash("sha256").update(projectDir).digest("hex").slice(0, 8);
12
+ return path.join(TMPDIR, `clabox-${path.basename(projectDir)}-${hash}.sb`);
13
+ }
14
+ /**
15
+ * Effective project dir: `config.cwd` (with `~` expanded, resolved to an
16
+ * absolute path so SBPL `subpath` rules stay valid) if set, else the shell CWD.
17
+ */
18
+ function resolveProjectDir(config) {
19
+ return config.cwd ? path.resolve(expandHome(config.cwd)) : process.cwd();
20
+ }
21
+ function which(bin) {
22
+ try {
23
+ return execFileSync("command", ["-v", bin], {
24
+ shell: "/bin/sh",
25
+ encoding: "utf8"
26
+ }).trim() || null;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+ function requireSandboxExec() {
32
+ if (!which("sandbox-exec")) throw new Error("sandbox-exec not found. This tool requires macOS with sandbox-exec.");
33
+ }
34
+ function resolveClaudeBin(config) {
35
+ const candidate = config.claudeBin || which("claude") || path.join(HOME, ".local/bin/claude");
36
+ if (!candidate || !fs.existsSync(candidate)) throw new Error(`claude not found at '${candidate}'`);
37
+ return candidate;
38
+ }
39
+ /** Generate the profile file for the current project, return its path. */
40
+ function generateProfile(config, projectDir = resolveProjectDir(config)) {
41
+ requireSandboxExec();
42
+ const file = profilePath(projectDir);
43
+ const text = buildProfile(config, {
44
+ projectDir,
45
+ detectedPaths: detectPackagePaths()
46
+ });
47
+ fs.writeFileSync(file, text);
48
+ return file;
49
+ }
50
+ /** Build the `env KEY=VALUE …` argument list forced onto the sandboxed claude. */
51
+ function buildEnvArgs(config) {
52
+ const sshDir = expandHome(config.bot.sshDir);
53
+ const botKey = path.join(sshDir, "id_ed25519");
54
+ const botCfg = path.join(sshDir, "config");
55
+ const args = [
56
+ `PATH=${path.join(HOME, ".local/bin")}:${process.env.PATH || ""}`,
57
+ `CLAUDE_CONFIG_DIR=${expandHome(config.configDir)}`,
58
+ `GIT_AUTHOR_NAME=${config.bot.name}`,
59
+ `GIT_AUTHOR_EMAIL=${config.bot.email}`,
60
+ `GIT_COMMITTER_NAME=${config.bot.name}`,
61
+ `GIT_COMMITTER_EMAIL=${config.bot.email}`,
62
+ "GIT_CONFIG_COUNT=2",
63
+ "GIT_CONFIG_KEY_0=commit.gpgsign",
64
+ "GIT_CONFIG_VALUE_0=false",
65
+ "GIT_CONFIG_KEY_1=tag.gpgsign",
66
+ "GIT_CONFIG_VALUE_1=false"
67
+ ];
68
+ if (fs.existsSync(botKey)) args.push(`GIT_SSH_COMMAND=ssh -F ${botCfg} -i ${botKey} -o IdentitiesOnly=yes -o IdentityAgent=none`);
69
+ for (const [key, value] of Object.entries(config.env ?? {})) args.push(`${key}=${value}`);
70
+ return args;
71
+ }
72
+ /** Generate the profile and exec claude under sandbox-exec. Returns exit code. */
73
+ function runClaude(config, claudeArgs, { configFile } = {}) {
74
+ const projectDir = resolveProjectDir(config);
75
+ const claudeBin = resolveClaudeBin(config);
76
+ const profileFile = generateProfile(config, projectDir);
77
+ if (process.env.CLABOX_DEBUG) {
78
+ console.error(`→ Running Claude Code sandboxed in: ${projectDir}`);
79
+ console.error(`→ Profile: ${profileFile}`);
80
+ console.error(`→ Config: ${expandHome(config.configDir)}`);
81
+ if (configFile) console.error(`→ Config file: ${configFile}`);
82
+ }
83
+ const title = projectDir.startsWith(HOME) ? `~${projectDir.slice(HOME.length)}` : projectDir;
84
+ process.stdout.write(`\x1b]0;${title}\x07`);
85
+ const envArgs = buildEnvArgs(config);
86
+ const defaultArgs = Array.isArray(config.claudeArgs) ? config.claudeArgs : [];
87
+ const inner = [
88
+ "sandbox-exec",
89
+ "-f",
90
+ profileFile,
91
+ "env",
92
+ ...envArgs,
93
+ claudeBin,
94
+ ...defaultArgs,
95
+ ...claudeArgs
96
+ ];
97
+ const res = spawnSync("/bin/sh", [
98
+ "-c",
99
+ `${config.ulimitProcs > 0 ? `ulimit -u ${config.ulimitProcs} 2>/dev/null; ` : ""}exec "$@"`,
100
+ "sh",
101
+ ...inner
102
+ ], {
103
+ cwd: projectDir,
104
+ stdio: "inherit"
105
+ });
106
+ if (res.error) throw res.error;
107
+ if (res.signal) return 1;
108
+ return res.status ?? 0;
109
+ }
110
+ //#endregion
111
+ export { runClaude as a, resolveProjectDir as i, generateProfile as n, profilePath as r, buildEnvArgs as t };
112
+
113
+ //# sourceMappingURL=run-CNehSQ-S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-CNehSQ-S.js","names":[],"sources":["../src/sandbox/run.ts"],"sourcesContent":["// Profile materialization + launching `claude` under sandbox-exec.\n\nimport { execFileSync, spawnSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { type Config, expandHome, HOME } from '../utils/config.js';\nimport { buildProfile, detectPackagePaths } from './profile.js';\n\nconst TMPDIR = (process.env.TMPDIR || '/tmp').replace(/\\/$/, '');\n\n/** Deterministic per-project profile path under TMPDIR. */\nexport function profilePath(projectDir: string = process.cwd()): string {\n const hash = crypto.createHash('sha256').update(projectDir).digest('hex').slice(0, 8);\n return path.join(TMPDIR, `clabox-${path.basename(projectDir)}-${hash}.sb`);\n}\n\n/**\n * Effective project dir: `config.cwd` (with `~` expanded, resolved to an\n * absolute path so SBPL `subpath` rules stay valid) if set, else the shell CWD.\n */\nexport function resolveProjectDir(config: Config): string {\n return config.cwd ? path.resolve(expandHome(config.cwd)) : process.cwd();\n}\n\nfunction which(bin: string): string | null {\n try {\n return (\n execFileSync('command', ['-v', bin], { shell: '/bin/sh', encoding: 'utf8' }).trim() || null\n );\n } catch {\n return null;\n }\n}\n\nfunction requireSandboxExec(): void {\n if (!which('sandbox-exec')) {\n throw new Error('sandbox-exec not found. This tool requires macOS with sandbox-exec.');\n }\n}\n\nfunction resolveClaudeBin(config: Config): string {\n const candidate = config.claudeBin || which('claude') || path.join(HOME, '.local/bin/claude');\n if (!candidate || !fs.existsSync(candidate)) {\n throw new Error(`claude not found at '${candidate}'`);\n }\n return candidate;\n}\n\n/** Generate the profile file for the current project, return its path. */\nexport function generateProfile(\n config: Config,\n projectDir: string = resolveProjectDir(config),\n): string {\n requireSandboxExec();\n const file = profilePath(projectDir);\n const text = buildProfile(config, { projectDir, detectedPaths: detectPackagePaths() });\n fs.writeFileSync(file, text);\n return file;\n}\n\n/** Build the `env KEY=VALUE …` argument list forced onto the sandboxed claude. */\nexport function buildEnvArgs(config: Config): string[] {\n const sshDir = expandHome(config.bot.sshDir);\n const botKey = path.join(sshDir, 'id_ed25519');\n const botCfg = path.join(sshDir, 'config');\n const args = [\n `PATH=${path.join(HOME, '.local/bin')}:${process.env.PATH || ''}`,\n `CLAUDE_CONFIG_DIR=${expandHome(config.configDir)}`,\n `GIT_AUTHOR_NAME=${config.bot.name}`,\n `GIT_AUTHOR_EMAIL=${config.bot.email}`,\n `GIT_COMMITTER_NAME=${config.bot.name}`,\n `GIT_COMMITTER_EMAIL=${config.bot.email}`,\n 'GIT_CONFIG_COUNT=2',\n 'GIT_CONFIG_KEY_0=commit.gpgsign',\n 'GIT_CONFIG_VALUE_0=false',\n 'GIT_CONFIG_KEY_1=tag.gpgsign',\n 'GIT_CONFIG_VALUE_1=false',\n ];\n // Pin git ssh to the bot key only when it actually exists, so the sandbox\n // stays usable without a dedicated bot key configured.\n if (fs.existsSync(botKey)) {\n args.push(\n `GIT_SSH_COMMAND=ssh -F ${botCfg} -i ${botKey} -o IdentitiesOnly=yes -o IdentityAgent=none`,\n );\n }\n // User-declared extras go last so they win over the built-in vars above\n // (duplicate keys: `env` keeps the last assignment).\n for (const [key, value] of Object.entries(config.env ?? {})) {\n args.push(`${key}=${value}`);\n }\n return args;\n}\n\n/** Options accepted by {@link runClaude}. */\nexport interface RunOptions {\n configFile?: string | null;\n}\n\n/** Generate the profile and exec claude under sandbox-exec. Returns exit code. */\nexport function runClaude(\n config: Config,\n claudeArgs: string[],\n { configFile }: RunOptions = {},\n): number {\n const projectDir = resolveProjectDir(config);\n const claudeBin = resolveClaudeBin(config);\n const profileFile = generateProfile(config, projectDir);\n\n if (process.env.CLABOX_DEBUG) {\n console.error(`→ Running Claude Code sandboxed in: ${projectDir}`);\n console.error(`→ Profile: ${profileFile}`);\n console.error(`→ Config: ${expandHome(config.configDir)}`);\n if (configFile) console.error(`→ Config file: ${configFile}`);\n }\n\n // Terminal title = cwd (with ~ for $HOME), matching the bash version.\n const title = projectDir.startsWith(HOME) ? `~${projectDir.slice(HOME.length)}` : projectDir;\n process.stdout.write(`\\x1b]0;${title}\\x07`);\n\n const envArgs = buildEnvArgs(config);\n const defaultArgs = Array.isArray(config.claudeArgs) ? config.claudeArgs : [];\n const inner = [\n 'sandbox-exec',\n '-f',\n profileFile,\n 'env',\n ...envArgs,\n claudeBin,\n ...defaultArgs,\n ...claudeArgs,\n ];\n\n // `ulimit` is a shell builtin; run the whole thing under sh so we can set it.\n // `exec \"$@\"` keeps argv intact without re-quoting (args start after $0=sh).\n const ulimit = config.ulimitProcs > 0 ? `ulimit -u ${config.ulimitProcs} 2>/dev/null; ` : '';\n const res = spawnSync('/bin/sh', ['-c', `${ulimit}exec \"$@\"`, 'sh', ...inner], {\n cwd: projectDir,\n stdio: 'inherit',\n });\n if (res.error) throw res.error;\n if (res.signal) return 1;\n return res.status ?? 0;\n}\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { i as Config } from "./config-DQWueb4a.js";
2
+
3
+ //#region src/sandbox/run.d.ts
4
+ /** Deterministic per-project profile path under TMPDIR. */
5
+ declare function profilePath(projectDir?: string): string;
6
+ /**
7
+ * Effective project dir: `config.cwd` (with `~` expanded, resolved to an
8
+ * absolute path so SBPL `subpath` rules stay valid) if set, else the shell CWD.
9
+ */
10
+ declare function resolveProjectDir(config: Config): string;
11
+ /** Generate the profile file for the current project, return its path. */
12
+ declare function generateProfile(config: Config, projectDir?: string): string;
13
+ /** Build the `env KEY=VALUE …` argument list forced onto the sandboxed claude. */
14
+ declare function buildEnvArgs(config: Config): string[];
15
+ /** Options accepted by {@link runClaude}. */
16
+ interface RunOptions {
17
+ configFile?: string | null;
18
+ }
19
+ /** Generate the profile and exec claude under sandbox-exec. Returns exit code. */
20
+ declare function runClaude(config: Config, claudeArgs: string[], {
21
+ configFile
22
+ }?: RunOptions): number;
23
+ //#endregion
24
+ export { resolveProjectDir as a, profilePath as i, buildEnvArgs as n, runClaude as o, generateProfile as r, RunOptions as t };
25
+ //# sourceMappingURL=run-Cx8cuTh5.d.ts.map
@@ -0,0 +1,2 @@
1
+ import { a as ipcName, c as regex, i as globalName, l as subpath, n as buildProfile, o as literal, r as detectPackagePaths, s as reEscape, t as ProfileContext } from "../profile-BeM41NXc.js";
2
+ export { ProfileContext, buildProfile, detectPackagePaths, globalName, ipcName, literal, reEscape, regex, subpath };
@@ -0,0 +1,2 @@
1
+ import { a as literal, c as subpath, i as ipcName, n as detectPackagePaths, o as reEscape, r as globalName, s as regex, t as buildProfile } from "../profile-DM6NAgb-.js";
2
+ export { buildProfile, detectPackagePaths, globalName, ipcName, literal, reEscape, regex, subpath };
@@ -0,0 +1,2 @@
1
+ import { a as resolveProjectDir, i as profilePath, n as buildEnvArgs, o as runClaude, r as generateProfile, t as RunOptions } from "../run-Cx8cuTh5.js";
2
+ export { RunOptions, buildEnvArgs, generateProfile, profilePath, resolveProjectDir, runClaude };
@@ -0,0 +1,2 @@
1
+ import { a as runClaude, i as resolveProjectDir, n as generateProfile, r as profilePath, t as buildEnvArgs } from "../run-CNehSQ-S.js";
2
+ export { buildEnvArgs, generateProfile, profilePath, resolveProjectDir, runClaude };
@@ -0,0 +1,46 @@
1
+ //#region src/init/scaffold.d.ts
2
+ /**
3
+ * Box names (sorted, de-duplicated) discovered in `<configsDir>` via the same
4
+ * rules as `-b`: both `<name>.mjs` and `<name>.config.mjs`, `_`-prefixed
5
+ * shared partials (e.g. `_presets.mjs`) skipped.
6
+ */
7
+ declare function discoverProfiles(configsDir: string): string[];
8
+ /** Options for {@link runInit}. */
9
+ interface InitOptions {
10
+ /** Base dir holding `configs/` and `scripts/`. Default: `<cwd>/__`. */
11
+ baseDir?: string;
12
+ /** Build the Ghostty apps for `app` boxes. Default: true. */
13
+ buildApps?: boolean;
14
+ /** Limit app building to a single box (by box name or app display name). */
15
+ only?: string | null;
16
+ }
17
+ /** A standalone Ghostty app built by `clabox init`. */
18
+ interface BuiltApp {
19
+ box: string;
20
+ appPath: string;
21
+ signed: 'identity' | 'adhoc';
22
+ }
23
+ /** Result of {@link runInit}. */
24
+ interface InitResult {
25
+ profiles: string[];
26
+ scriptsDir: string;
27
+ indexFile: string;
28
+ written: string[];
29
+ /** Apps successfully built. */
30
+ apps: BuiltApp[];
31
+ /** Generated Ghostty config files. */
32
+ ghosttyConfigs: string[];
33
+ /** Generated Raycast command scripts. */
34
+ raycastCommands: string[];
35
+ /** Non-fatal issues (e.g. app build skipped/failed). */
36
+ warnings: string[];
37
+ }
38
+ /** Scan the configs dir, (re)write the alias scripts, and build `app` apps. */
39
+ declare function runInit({
40
+ baseDir,
41
+ buildApps,
42
+ only
43
+ }?: InitOptions): Promise<InitResult>;
44
+ //#endregion
45
+ export { runInit as a, discoverProfiles as i, InitOptions as n, InitResult as r, BuiltApp as t };
46
+ //# sourceMappingURL=scaffold-ByIbYAeS.d.ts.map
@@ -0,0 +1,141 @@
1
+ import { i as expandHome, l as resolveBox, o as listBoxes, s as loadConfig } from "./config-BQ44iVWT.js";
2
+ import { n as buildAliasFiles } from "./aliases-DKGcMHHe.js";
3
+ import { r as buildGhosttyConfig, t as appBundlePath } from "./ghostty-Ca0g9P9P.js";
4
+ import { n as canBuildApps, t as buildApp } from "./app-CieBa29D.js";
5
+ import { t as buildRaycastCommand } from "./raycast-BCdO2Se1.js";
6
+ import path from "node:path";
7
+ import { execFileSync } from "node:child_process";
8
+ import fs from "node:fs";
9
+ //#region src/init/scaffold.ts
10
+ /**
11
+ * Box names (sorted, de-duplicated) discovered in `<configsDir>` via the same
12
+ * rules as `-b`: both `<name>.mjs` and `<name>.config.mjs`, `_`-prefixed
13
+ * shared partials (e.g. `_presets.mjs`) skipped.
14
+ */
15
+ function discoverProfiles(configsDir) {
16
+ if (!fs.existsSync(configsDir)) throw new Error(`clabox init: configs dir not found: ${configsDir}`);
17
+ const names = listBoxes(configsDir);
18
+ if (names.length === 0) throw new Error(`clabox init: no box configs (*.mjs) in ${configsDir}`);
19
+ return names;
20
+ }
21
+ /** Remove previously generated artifacts (`index.sh`, `clabox-*.sh`). */
22
+ function pruneGenerated(scriptsDir) {
23
+ if (!fs.existsSync(scriptsDir)) return;
24
+ for (const f of fs.readdirSync(scriptsDir)) if (f === "index.sh" || f.startsWith("clabox-") && f.endsWith(".sh")) fs.rmSync(path.join(scriptsDir, f), { force: true });
25
+ }
26
+ /** Remove files in `dir` whose name ends with `ext` (a no-op if dir is absent). */
27
+ function pruneByExt(dir, ext) {
28
+ if (!fs.existsSync(dir)) return;
29
+ for (const f of fs.readdirSync(dir)) if (f.endsWith(ext)) fs.rmSync(path.join(dir, f), { force: true });
30
+ }
31
+ /** Locate the `clabox` binary to bake into the generated Ghostty `command`. */
32
+ function resolveClaboxBin(configured) {
33
+ if (configured) return expandHome(configured);
34
+ try {
35
+ const found = execFileSync("command", ["-v", "clabox"], {
36
+ shell: "/bin/sh",
37
+ encoding: "utf8"
38
+ }).trim();
39
+ if (found) return found;
40
+ } catch {}
41
+ return "clabox";
42
+ }
43
+ /** Generate the Ghostty configs and build the apps for every `app` box. */
44
+ async function buildAppArtifacts(base, configsDir, profiles, only, result) {
45
+ const appBoxes = [];
46
+ for (const name of profiles) {
47
+ const { config } = await loadConfig(resolveBox(name, configsDir));
48
+ if (!config.app) continue;
49
+ if (only && name !== only && config.app.name !== only) continue;
50
+ appBoxes.push({
51
+ name,
52
+ config
53
+ });
54
+ }
55
+ if (appBoxes.length === 0) return;
56
+ const ghosttyDir = path.join(base, "ghostty");
57
+ const raycastDir = path.join(base, "raycast");
58
+ fs.mkdirSync(ghosttyDir, { recursive: true });
59
+ fs.mkdirSync(raycastDir, { recursive: true });
60
+ if (!only) {
61
+ pruneByExt(ghosttyDir, ".config");
62
+ pruneByExt(raycastDir, ".sh");
63
+ }
64
+ for (const { name, config } of appBoxes) {
65
+ const app = config.app;
66
+ if (!app) continue;
67
+ const configPath = path.join(ghosttyDir, `${name}.config`);
68
+ const projectDir = config.cwd ? path.resolve(expandHome(config.cwd)) : null;
69
+ const baseGhostty = config.appBuilder.baseGhosttyConfig ? expandHome(config.appBuilder.baseGhosttyConfig) : null;
70
+ fs.writeFileSync(configPath, buildGhosttyConfig({
71
+ app,
72
+ boxName: name,
73
+ projectDir,
74
+ configsDir,
75
+ claboxBin: resolveClaboxBin(config.appBuilder.claboxBin),
76
+ baseGhosttyConfig: baseGhostty
77
+ }));
78
+ result.ghosttyConfigs.push(configPath);
79
+ const appPath = appBundlePath(expandHome(config.appBuilder.appsDir), app);
80
+ const raycastPath = path.join(raycastDir, `${name}.sh`);
81
+ fs.writeFileSync(raycastPath, buildRaycastCommand({
82
+ app,
83
+ appPath
84
+ }));
85
+ fs.chmodSync(raycastPath, 493);
86
+ result.raycastCommands.push(raycastPath);
87
+ const check = canBuildApps(config.appBuilder);
88
+ if (!check.ok) {
89
+ result.warnings.push(`${name}: app not built (${check.reason})`);
90
+ continue;
91
+ }
92
+ try {
93
+ const built = buildApp({
94
+ boxName: name,
95
+ app,
96
+ builder: config.appBuilder,
97
+ configPath
98
+ });
99
+ result.apps.push({
100
+ box: name,
101
+ appPath: built.appPath,
102
+ signed: built.signed
103
+ });
104
+ } catch (e) {
105
+ result.warnings.push(`${name}: app build failed — ${e.message}`);
106
+ }
107
+ }
108
+ }
109
+ /** Scan the configs dir, (re)write the alias scripts, and build `app` apps. */
110
+ async function runInit({ baseDir, buildApps = true, only = null } = {}) {
111
+ const base = path.resolve(baseDir ?? path.join(process.cwd(), "__"));
112
+ const configsDir = path.join(base, "configs");
113
+ const scriptsDir = path.join(base, "scripts");
114
+ const profiles = discoverProfiles(configsDir);
115
+ fs.mkdirSync(scriptsDir, { recursive: true });
116
+ pruneGenerated(scriptsDir);
117
+ const files = buildAliasFiles(profiles, {
118
+ configsDir,
119
+ scriptsDir
120
+ });
121
+ for (const f of files) {
122
+ fs.writeFileSync(f.path, f.content);
123
+ if (f.executable) fs.chmodSync(f.path, 493);
124
+ }
125
+ const result = {
126
+ profiles,
127
+ scriptsDir,
128
+ indexFile: path.join(scriptsDir, "index.sh"),
129
+ written: files.map((f) => f.path),
130
+ apps: [],
131
+ ghosttyConfigs: [],
132
+ raycastCommands: [],
133
+ warnings: []
134
+ };
135
+ if (buildApps) await buildAppArtifacts(base, configsDir, profiles, only, result);
136
+ return result;
137
+ }
138
+ //#endregion
139
+ export { runInit as n, discoverProfiles as t };
140
+
141
+ //# sourceMappingURL=scaffold-CRzC5KYe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold-CRzC5KYe.js","names":[],"sources":["../src/init/scaffold.ts"],"sourcesContent":["// I/O for `clabox init`: discover the box configs in `<base>/configs/`,\n// (re)write the shell aliases into `<base>/scripts/`, and — for boxes that opt\n// in via `app` — generate a Ghostty config in `<base>/ghostty/` and build a\n// standalone `<appsDir>/<name>.app` (see init/app.ts).\n\nimport { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { type Config, expandHome, listBoxes, loadConfig, resolveBox } from '../utils/config.js';\nimport { buildAliasFiles } from './aliases.js';\nimport { buildApp, canBuildApps } from './app.js';\nimport { appBundlePath, buildGhosttyConfig } from './ghostty.js';\nimport { buildRaycastCommand } from './raycast.js';\n\n/**\n * Box names (sorted, de-duplicated) discovered in `<configsDir>` via the same\n * rules as `-b`: both `<name>.mjs` and `<name>.config.mjs`, `_`-prefixed\n * shared partials (e.g. `_presets.mjs`) skipped.\n */\nexport function discoverProfiles(configsDir: string): string[] {\n if (!fs.existsSync(configsDir)) {\n throw new Error(`clabox init: configs dir not found: ${configsDir}`);\n }\n const names = listBoxes(configsDir);\n if (names.length === 0) {\n throw new Error(`clabox init: no box configs (*.mjs) in ${configsDir}`);\n }\n return names;\n}\n\n/** Remove previously generated artifacts (`index.sh`, `clabox-*.sh`). */\nfunction pruneGenerated(scriptsDir: string): void {\n if (!fs.existsSync(scriptsDir)) return;\n for (const f of fs.readdirSync(scriptsDir)) {\n if (f === 'index.sh' || (f.startsWith('clabox-') && f.endsWith('.sh'))) {\n fs.rmSync(path.join(scriptsDir, f), { force: true });\n }\n }\n}\n\n/** Remove files in `dir` whose name ends with `ext` (a no-op if dir is absent). */\nfunction pruneByExt(dir: string, ext: string): void {\n if (!fs.existsSync(dir)) return;\n for (const f of fs.readdirSync(dir)) {\n if (f.endsWith(ext)) fs.rmSync(path.join(dir, f), { force: true });\n }\n}\n\n/** Locate the `clabox` binary to bake into the generated Ghostty `command`. */\nfunction resolveClaboxBin(configured: string | null): string {\n if (configured) return expandHome(configured);\n try {\n const found = execFileSync('command', ['-v', 'clabox'], {\n shell: '/bin/sh',\n encoding: 'utf8',\n }).trim();\n if (found) return found;\n } catch {\n // fall through\n }\n return 'clabox';\n}\n\n/** Options for {@link runInit}. */\nexport interface InitOptions {\n /** Base dir holding `configs/` and `scripts/`. Default: `<cwd>/__`. */\n baseDir?: string;\n /** Build the Ghostty apps for `app` boxes. Default: true. */\n buildApps?: boolean;\n /** Limit app building to a single box (by box name or app display name). */\n only?: string | null;\n}\n\n/** A standalone Ghostty app built by `clabox init`. */\nexport interface BuiltApp {\n box: string;\n appPath: string;\n signed: 'identity' | 'adhoc';\n}\n\n/** Result of {@link runInit}. */\nexport interface InitResult {\n profiles: string[];\n scriptsDir: string;\n indexFile: string;\n written: string[];\n /** Apps successfully built. */\n apps: BuiltApp[];\n /** Generated Ghostty config files. */\n ghosttyConfigs: string[];\n /** Generated Raycast command scripts. */\n raycastCommands: string[];\n /** Non-fatal issues (e.g. app build skipped/failed). */\n warnings: string[];\n}\n\n/** Generate the Ghostty configs and build the apps for every `app` box. */\nasync function buildAppArtifacts(\n base: string,\n configsDir: string,\n profiles: string[],\n only: string | null,\n result: InitResult,\n): Promise<void> {\n // Load each box config; keep the ones that opt into an app (and match `only`).\n const appBoxes: { name: string; config: Config }[] = [];\n for (const name of profiles) {\n const { config } = await loadConfig(resolveBox(name, configsDir));\n if (!config.app) continue;\n if (only && name !== only && config.app.name !== only) continue;\n appBoxes.push({ name, config });\n }\n if (appBoxes.length === 0) return;\n\n const ghosttyDir = path.join(base, 'ghostty');\n const raycastDir = path.join(base, 'raycast');\n fs.mkdirSync(ghosttyDir, { recursive: true });\n fs.mkdirSync(raycastDir, { recursive: true });\n // Only prune on a full run — with `only` we'd orphan other apps' artifacts.\n if (!only) {\n pruneByExt(ghosttyDir, '.config');\n pruneByExt(raycastDir, '.sh');\n }\n\n for (const { name, config } of appBoxes) {\n const app = config.app;\n if (!app) continue; // narrowed above; keeps the type checker happy\n const configPath = path.join(ghosttyDir, `${name}.config`);\n const projectDir = config.cwd ? path.resolve(expandHome(config.cwd)) : null;\n const baseGhostty = config.appBuilder.baseGhosttyConfig\n ? expandHome(config.appBuilder.baseGhosttyConfig)\n : null;\n fs.writeFileSync(\n configPath,\n buildGhosttyConfig({\n app,\n boxName: name,\n projectDir,\n configsDir,\n claboxBin: resolveClaboxBin(config.appBuilder.claboxBin),\n baseGhosttyConfig: baseGhostty,\n }),\n );\n result.ghosttyConfigs.push(configPath);\n\n // Raycast command that opens the (to be) built bundle.\n const appPath = appBundlePath(expandHome(config.appBuilder.appsDir), app);\n const raycastPath = path.join(raycastDir, `${name}.sh`);\n fs.writeFileSync(raycastPath, buildRaycastCommand({ app, appPath }));\n fs.chmodSync(raycastPath, 0o755);\n result.raycastCommands.push(raycastPath);\n\n const check = canBuildApps(config.appBuilder);\n if (!check.ok) {\n result.warnings.push(`${name}: app not built (${check.reason})`);\n continue;\n }\n try {\n const built = buildApp({ boxName: name, app, builder: config.appBuilder, configPath });\n result.apps.push({ box: name, appPath: built.appPath, signed: built.signed });\n } catch (e) {\n result.warnings.push(`${name}: app build failed — ${(e as Error).message}`);\n }\n }\n}\n\n/** Scan the configs dir, (re)write the alias scripts, and build `app` apps. */\nexport async function runInit({\n baseDir,\n buildApps = true,\n only = null,\n}: InitOptions = {}): Promise<InitResult> {\n const base = path.resolve(baseDir ?? path.join(process.cwd(), '__'));\n const configsDir = path.join(base, 'configs');\n const scriptsDir = path.join(base, 'scripts');\n const profiles = discoverProfiles(configsDir);\n\n fs.mkdirSync(scriptsDir, { recursive: true });\n pruneGenerated(scriptsDir);\n\n const files = buildAliasFiles(profiles, { configsDir, scriptsDir });\n for (const f of files) {\n fs.writeFileSync(f.path, f.content);\n if (f.executable) fs.chmodSync(f.path, 0o755);\n }\n\n const result: InitResult = {\n profiles,\n scriptsDir,\n indexFile: path.join(scriptsDir, 'index.sh'),\n written: files.map((f) => f.path),\n apps: [],\n ghosttyConfigs: [],\n raycastCommands: [],\n warnings: [],\n };\n\n if (buildApps) {\n await buildAppArtifacts(base, configsDir, profiles, only, result);\n }\n return result;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { a as HOME, c as configsDir, d as findConfigFile, f as listBoxes, h as resolveBox, i as Config, l as defaultConfig, m as mergeConfig, n as AppConfig, o as LoadedConfig, p as loadConfig, r as BotConfig, s as PathRules, t as AppBuilderConfig, u as expandHome } from "../config-DQWueb4a.js";
2
+ export { AppBuilderConfig, AppConfig, BotConfig, Config, HOME, LoadedConfig, PathRules, configsDir, defaultConfig, expandHome, findConfigFile, listBoxes, loadConfig, mergeConfig, resolveBox };
@@ -0,0 +1,2 @@
1
+ import { a as findConfigFile, c as mergeConfig, i as expandHome, l as resolveBox, n as configsDir, o as listBoxes, r as defaultConfig, s as loadConfig, t as HOME } from "../config-BQ44iVWT.js";
2
+ export { HOME, configsDir, defaultConfig, expandHome, findConfigFile, listBoxes, loadConfig, mergeConfig, resolveBox };
package/package.json CHANGED
@@ -1,12 +1,146 @@
1
1
  {
2
2
  "name": "clabox",
3
- "version": "0.0.1",
4
- "description": "",
5
- "main": "index.js",
3
+ "version": "0.1.0",
4
+ "description": "Run Claude Code in a sandbox for super-safe YOLO mode",
5
+ "type": "module",
6
+ "author": "Igor Suvorov",
7
+ "license": "MIT",
8
+ "bin": {
9
+ "clabox": "lib/cli.js"
10
+ },
11
+ "main": "lib/index.js",
12
+ "types": "lib/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./lib/index.js",
16
+ "types": "./lib/index.d.ts",
17
+ "default": "./lib/index.js"
18
+ },
19
+ "./cli": {
20
+ "import": "./lib/cli.js",
21
+ "types": "./lib/cli.d.ts",
22
+ "default": "./lib/cli.js"
23
+ },
24
+ "./config": {
25
+ "import": "./lib/utils/config.js",
26
+ "types": "./lib/utils/config.d.ts",
27
+ "default": "./lib/utils/config.js"
28
+ },
29
+ "./profile": {
30
+ "import": "./lib/sandbox/profile.js",
31
+ "types": "./lib/sandbox/profile.d.ts",
32
+ "default": "./lib/sandbox/profile.js"
33
+ },
34
+ "./run": {
35
+ "import": "./lib/sandbox/run.js",
36
+ "types": "./lib/sandbox/run.d.ts",
37
+ "default": "./lib/sandbox/run.js"
38
+ },
39
+ "./*": "./lib/*"
40
+ },
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "files": [
45
+ "lib",
46
+ "docs",
47
+ "clabox.config.example.mjs",
48
+ "README.md",
49
+ "LICENSE"
50
+ ],
6
51
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
52
+ "build:tsdown": "tsdown",
53
+ "build:tsdown:release": "tsdown --out-dir lib",
54
+ "build": "bun run build:tsdown:release",
55
+ "dev": "tsdown --watch",
56
+ "cli": "bun run src/cli.ts",
57
+ "generate": "bun run src/cli.ts generate",
58
+ "test:unit": "bun test",
59
+ "test:unit:coverage": "bun test --coverage",
60
+ "test:unit:watch": "bun test --watch",
61
+ "test:types": "tsc --noEmit",
62
+ "test:lint": "biome lint",
63
+ "test:size": "size-limit",
64
+ "test": "bun run test:lint && bun run test:types && bun run test:unit && bun run test:size",
65
+ "fix:lint": "biome check --write",
66
+ "fix:lint:unsafe": "biome check --write --unsafe",
67
+ "fix": "bun run fix:lint",
68
+ "version:release": "semantic-release --no-ci --dry-run",
69
+ "release": "bun run build && bun run test && bun run version:release && npm publish"
70
+ },
71
+ "size-limit": [
72
+ {
73
+ "path": "lib/index.js",
74
+ "limit": "10 kb",
75
+ "ignore": [
76
+ "node:*"
77
+ ]
78
+ }
79
+ ],
80
+ "dependencies": {
81
+ "yargs": "^17.7.2"
82
+ },
83
+ "release": {
84
+ "branches": [
85
+ "main"
86
+ ],
87
+ "plugins": [
88
+ "@semantic-release/commit-analyzer",
89
+ "@semantic-release/release-notes-generator",
90
+ "@semantic-release/changelog",
91
+ [
92
+ "@semantic-release/npm",
93
+ {
94
+ "npmPublish": true
95
+ }
96
+ ],
97
+ "@semantic-release/github",
98
+ [
99
+ "@semantic-release/git",
100
+ {
101
+ "assets": [
102
+ "package.json",
103
+ "CHANGELOG.md",
104
+ "bun.lock"
105
+ ],
106
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
107
+ }
108
+ ]
109
+ ]
110
+ },
111
+ "publishConfig": {
112
+ "access": "public",
113
+ "provenance": true
114
+ },
115
+ "keywords": [
116
+ "claude",
117
+ "claude-code",
118
+ "sandbox",
119
+ "seatbelt",
120
+ "sandbox-exec",
121
+ "macos",
122
+ "security",
123
+ "cli"
124
+ ],
125
+ "repository": {
126
+ "type": "git",
127
+ "url": "git+https://github.com/ycmds/clabox.git"
128
+ },
129
+ "homepage": "https://github.com/ycmds/clabox#readme",
130
+ "bugs": {
131
+ "url": "https://github.com/ycmds/clabox/issues"
8
132
  },
9
- "keywords": [],
10
- "author": "",
11
- "license": "ISC"
133
+ "devDependencies": {
134
+ "@biomejs/biome": "^2.5.0",
135
+ "@semantic-release/changelog": "^6.0.3",
136
+ "@semantic-release/git": "^10.0.1",
137
+ "@size-limit/preset-small-lib": "^12.1.0",
138
+ "@types/bun": "^1.3.14",
139
+ "@types/node": "^26.0.0",
140
+ "@types/yargs": "^17.0.35",
141
+ "semantic-release": "^25.0.5",
142
+ "size-limit": "^12.1.0",
143
+ "tsdown": "^0.22.3",
144
+ "typescript": "^6.0.3"
145
+ }
12
146
  }