clabox 0.0.2 → 0.1.1

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 (52) hide show
  1. package/README.md +30 -0
  2. package/clabox.config.example.mjs +44 -0
  3. package/docs/guideline.md +43 -10
  4. package/lib/aliases-DKGcMHHe.js +60 -0
  5. package/lib/aliases-DKGcMHHe.js.map +1 -0
  6. package/lib/aliases-DXyz-ufw.d.ts +31 -0
  7. package/lib/app-CQmESEdh.js +254 -0
  8. package/lib/app-CQmESEdh.js.map +1 -0
  9. package/lib/app-DzQ5yZfD.d.ts +32 -0
  10. package/lib/cli.js +46 -9
  11. package/lib/cli.js.map +1 -1
  12. package/lib/{config-DXTNeUhH.js → config-BQ44iVWT.js} +56 -4
  13. package/lib/config-BQ44iVWT.js.map +1 -0
  14. package/lib/config-DQWueb4a.d.ts +134 -0
  15. package/lib/ghostty-By4zmOuk.d.ts +34 -0
  16. package/lib/ghostty-DcMEZ6Ey.js +74 -0
  17. package/lib/ghostty-DcMEZ6Ey.js.map +1 -0
  18. package/lib/index.d.ts +9 -4
  19. package/lib/index.js +9 -4
  20. package/lib/init/aliases.d.ts +2 -0
  21. package/lib/init/aliases.js +2 -0
  22. package/lib/init/app.d.ts +2 -0
  23. package/lib/init/app.js +2 -0
  24. package/lib/init/ghostty.d.ts +2 -0
  25. package/lib/init/ghostty.js +2 -0
  26. package/lib/init/raycast.d.ts +2 -0
  27. package/lib/init/raycast.js +2 -0
  28. package/lib/init/scaffold.d.ts +2 -0
  29. package/lib/init/scaffold.js +2 -0
  30. package/lib/{profile-Bw6L1MiV.d.ts → profile-BeM41NXc.d.ts} +2 -2
  31. package/lib/{profile-CxqsgezL.js → profile-DM6NAgb-.js} +9 -12
  32. package/lib/profile-DM6NAgb-.js.map +1 -0
  33. package/lib/raycast-BCdO2Se1.js +35 -0
  34. package/lib/raycast-BCdO2Se1.js.map +1 -0
  35. package/lib/raycast-DM7c559f.d.ts +22 -0
  36. package/lib/{run-Dyp_hW97.js → run-CNehSQ-S.js} +20 -11
  37. package/lib/run-CNehSQ-S.js.map +1 -0
  38. package/lib/{run-BfF3Cwg7.d.ts → run-Cx8cuTh5.d.ts} +10 -3
  39. package/lib/sandbox/profile.d.ts +1 -1
  40. package/lib/sandbox/profile.js +1 -1
  41. package/lib/sandbox/run.d.ts +2 -2
  42. package/lib/sandbox/run.js +2 -2
  43. package/lib/scaffold-B7pUVGoC.js +141 -0
  44. package/lib/scaffold-B7pUVGoC.js.map +1 -0
  45. package/lib/scaffold-ByIbYAeS.d.ts +46 -0
  46. package/lib/utils/config.d.ts +2 -2
  47. package/lib/utils/config.js +2 -2
  48. package/package.json +1 -1
  49. package/lib/config-CUyriGxm.d.ts +0 -67
  50. package/lib/config-DXTNeUhH.js.map +0 -1
  51. package/lib/profile-CxqsgezL.js.map +0 -1
  52. package/lib/run-Dyp_hW97.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"profile-CxqsgezL.js","names":[],"sources":["../src/sandbox/profile.ts"],"sourcesContent":["// Seatbelt (SBPL) profile generator.\n//\n// The old bash version baked the profile into a heredoc and patched it with\n// sed. Here the profile is assembled from small typed helpers, so the parts\n// you actually want to tweak live in config.ts as plain data.\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { type Config, expandHome, HOME } from '../utils/config.js';\n\n// ---- SBPL helpers ----------------------------------------------------------\n\n// Quote a literal string for SBPL. Only `\"` needs escaping; backslashes are\n// left as-is so regex patterns survive verbatim.\nconst q = (s: string): string => `\"${String(s).replace(/\"/g, '\\\\\"')}\"`;\n\nexport const subpath = (p: string): string => `(subpath ${q(p)})`;\nexport const literal = (p: string): string => `(literal ${q(p)})`;\nexport const regex = (p: string): string => `(regex ${q(p)})`;\nexport const globalName = (n: string): string => `(global-name ${q(n)})`;\nexport const ipcName = (n: string): string => `(ipc-posix-name ${q(n)})`;\n\n/** Escape a path for safe embedding inside an SBPL regex. */\nexport const reEscape = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nfunction block(op: string, rules: string[]): string {\n return [`(${op}`, ...rules.map((r) => ` ${r}`), ')'].join('\\n');\n}\nconst allow = (op: string, ...rules: string[]): string => block(`allow ${op}`, rules);\nconst deny = (op: string, ...rules: string[]): string => block(`deny ${op}`, rules);\n\n// ---- package-manager autodetection ----------------------------------------\n\n/** Detect installed package managers whose paths must be readable/executable. */\nexport function detectPackagePaths(): string[] {\n const paths: string[] = [];\n if (fs.existsSync('/opt/homebrew')) paths.push('/opt/homebrew');\n else if (fs.existsSync('/usr/local/Homebrew')) paths.push('/usr/local/Homebrew');\n const local = path.join(HOME, '.local');\n if (fs.existsSync(local)) paths.push(local);\n if (fs.existsSync('/nix/store')) paths.push('/nix/store');\n return paths;\n}\n\n/** Context needed to assemble a profile for a specific project. */\nexport interface ProfileContext {\n projectDir: string;\n detectedPaths?: string[];\n}\n\n/**\n * Build the full SBPL profile text.\n * @param config effective config (see config.ts)\n * @param ctx { projectDir, detectedPaths }\n */\nexport function buildProfile(\n config: Config,\n { projectDir, detectedPaths = detectPackagePaths() }: ProfileContext,\n): string {\n const configDir = expandHome(config.configDir);\n const sshDir = expandHome(config.bot.sshDir);\n const hooksDir = config.hooksDir ? expandHome(config.hooksDir) : null;\n const homeRe = reEscape(HOME);\n\n const sections: string[] = [];\n const add = (comment: string, body: string) => sections.push(`;; ---------- ${comment}\\n${body}`);\n\n sections.push(\n [\n ';; ------------------------------------------------------------------',\n ';; Claude Code macOS sandbox profile (autogenerated)',\n ';; ------------------------------------------------------------------',\n '(version 1)',\n '(deny default)',\n ].join('\\n'),\n );\n\n add('introspection & sysctl', '(allow file-read-metadata)\\n(allow sysctl-read)');\n\n add(\n 'basic dir traversal',\n [\n allow('file-read*', literal('/')),\n allow('file-read*', literal('/private')),\n allow('file-read-data', literal('/Users')),\n allow('file-read-data', literal(HOME)),\n ].join('\\n'),\n );\n\n add(\n 'system runtime (read-only)',\n allow(\n 'file-read* file-map-executable',\n subpath('/System'),\n subpath('/usr'),\n subpath('/bin'),\n subpath('/sbin'),\n subpath('/Library/Frameworks'),\n subpath('/private/etc'),\n subpath('/var/db/dyld'),\n ...detectedPaths.map(subpath),\n ),\n );\n\n add(\n 'Xcode / Command Line Tools (xcrun, git, etc.)',\n [\n allow(\n 'file-read* file-map-executable',\n subpath('/Library/Developer/CommandLineTools'),\n subpath('/Applications/Xcode.app'),\n ),\n allow(\n 'process-exec',\n subpath('/Library/Developer/CommandLineTools'),\n subpath('/Applications/Xcode.app'),\n ),\n ].join('\\n'),\n );\n\n // global npm/pipx/cargo bins (user-installed)\n const userPaths = detectedPaths.filter((p) => p.endsWith('/.local'));\n add(\n 'global npm/pipx/cargo bins',\n userPaths.length\n ? userPaths.map((p) => allow('file-read*', subpath(p))).join('\\n')\n : ';; No user package paths detected',\n );\n\n add(\n 'executable paths',\n allow(\n 'process-exec',\n subpath('/usr'),\n subpath('/System'),\n subpath('/bin'),\n subpath('/sbin'),\n literal('/usr/bin/env'),\n ...detectedPaths.map(subpath),\n ),\n );\n\n add(\n 'temp dirs',\n allow(\n 'file-read* file-write*',\n subpath('/tmp'),\n subpath('/private/tmp'),\n regex('^/private/var/folders/'),\n ),\n );\n\n add('Claude config & token files', allow('file-read* file-write*', subpath(configDir)));\n\n add(\n 'Claude auto-update (RO) -- suppress warnings',\n allow(\n 'file-read*',\n subpath(path.join(HOME, '.local/state/claude')),\n subpath(path.join(HOME, '.cache/claude')),\n ),\n );\n\n add(\n 'time-zone & prefs (RO)',\n allow('file-read*', subpath('/private/var/db/timezone'), subpath('/Library/Preferences')),\n );\n\n add(\n '/dev access (RO) + ioctl',\n [\n allow('file-read*', literal('/dev')),\n allow('file-read* file-write*', regex('^/dev/(tty.*|null|zero|dtracehelper)')),\n allow('file-ioctl', literal('/dev/dtracehelper'), regex('^/dev/tty.*')),\n ].join('\\n'),\n );\n\n add(\n 'mach-lookup services',\n allow(\n 'mach-lookup',\n globalName('com.apple.system.opendirectoryd.libinfo'),\n globalName('com.apple.SystemConfiguration.DNSConfiguration'),\n globalName('com.apple.coreservices.launchservicesd'),\n globalName('com.apple.CoreServices.coreservicesd'),\n globalName('com.apple.system.notification_center'),\n globalName('com.apple.logd'),\n globalName('com.apple.diagnosticd'),\n globalName('com.apple.lsd.mapdb'),\n globalName('com.apple.lsd.modifydb'),\n globalName('com.apple.coreservices.quarantine-resolver'),\n globalName('com.apple.pasteboard.pboard'),\n globalName('com.apple.pasteboard.1'),\n ),\n );\n\n add(\n 'Launch Services needed by /usr/bin/open',\n allow('mach-lookup', regex('^com\\\\.apple\\\\.lsd(\\\\..*)?$')),\n );\n\n add(\n 'Developer Tools (xcrun / libxcrun)',\n allow('mach-lookup', globalName('com.apple.dt.xcsecurity'), regex('^com\\\\.apple\\\\.dt\\\\..*$')),\n );\n\n add(\n 'Audio (afplay)',\n allow(\n 'mach-lookup',\n globalName('com.apple.audio.audiohald'),\n globalName('com.apple.audio.AudioComponentRegistrar'),\n ),\n );\n\n add(\n 'Notification Center shared-memory (RO)',\n allow('ipc-posix-shm-read-data', ipcName('apple.shm.notification_center')),\n );\n\n add(\n 'User-level preference reads (RO)',\n allow('file-read*', subpath(path.join(HOME, 'Library/Preferences'))),\n );\n\n // Keychain RW so Claude can persist refreshed OAuth tokens (else ~24h → 401).\n add(\n 'Keychain access (for OAuth)',\n [\n allow('file-read* file-write*', subpath(path.join(HOME, 'Library/Keychains'))),\n allow(\n 'mach-lookup',\n globalName('com.apple.SecurityServer'),\n globalName('com.apple.security.agent'),\n globalName('com.apple.securityd'),\n globalName('com.apple.secd'),\n globalName('com.apple.trustd'),\n globalName('com.apple.trustd.agent'),\n globalName('com.apple.CoreAuthentication.daemon'),\n ),\n ].join('\\n'),\n );\n\n add(\n 'git config (RO)',\n allow(\n 'file-read*',\n literal(path.join(HOME, '.gitconfig')),\n literal(path.join(HOME, '.gitignore_global')),\n subpath(path.join(HOME, '.config/git')),\n ),\n );\n\n // Explicit deny list — wins even over allows above.\n const denyRules = [...config.denyHome.map((d) => subpath(path.join(HOME, d)))];\n if (config.denyDotConfigs.length) {\n denyRules.push(regex(`^${homeRe}/\\\\.(${config.denyDotConfigs.join('|')})($|/)`));\n }\n denyRules.push(...config.paths.deny.map((p) => subpath(expandHome(p))));\n add('explicit sensitive DENY list', deny('file-read* file-write*', ...denyRules));\n\n add(\n 'SSH: bot key only, deny other keys',\n [\n allow(\n 'file-read*',\n literal(path.join(HOME, '.ssh')),\n literal(path.join(HOME, '.ssh/known_hosts')),\n literal(path.join(HOME, '.ssh/known_hosts2')),\n literal(path.join(HOME, '.ssh/config')),\n subpath(sshDir),\n ),\n allow(\n 'file-write*',\n literal(path.join(HOME, '.ssh/known_hosts')),\n literal(path.join(HOME, '.ssh/known_hosts2')),\n ),\n deny(\n 'file-read* file-write*',\n regex(`^${homeRe}/\\\\.ssh/id_`),\n regex(`^${homeRe}/\\\\.ssh/.*\\\\.pem$`),\n regex(`^${homeRe}/\\\\.ssh/.*\\\\.key$`),\n ),\n ].join('\\n'),\n );\n\n add(\n 'claude hooks (RO + exec)',\n hooksDir && fs.existsSync(hooksDir)\n ? [\n allow('file-read* file-map-executable', subpath(hooksDir)),\n allow('process-exec', subpath(hooksDir)),\n ].join('\\n')\n : ';; (no hooks dir; set config.hooksDir / CLABOX_HOOKS_DIR to enable)',\n );\n\n // Extra user-supplied RO / RW / exec rules.\n if (config.paths.readOnly.length)\n add(\n 'extra read-only paths',\n allow('file-read*', ...config.paths.readOnly.map((p) => subpath(expandHome(p)))),\n );\n if (config.paths.readWrite.length)\n add(\n 'extra read-write paths',\n allow('file-read* file-write*', ...config.paths.readWrite.map((p) => subpath(expandHome(p)))),\n );\n if (config.paths.exec.length)\n add(\n 'extra exec paths',\n allow('process-exec', ...config.paths.exec.map((p) => subpath(expandHome(p)))),\n );\n\n add(\n 'project workspace (RW)',\n [\n allow('file-read* file-write* file-map-executable', subpath(projectDir)),\n allow('process-exec', subpath(projectDir)),\n ].join('\\n'),\n );\n\n if (config.network) add('networking', '(allow network*)');\n\n sections.push('(allow process-fork)\\n(allow lsopen)');\n\n const text = `${sections.join('\\n\\n')}\\n`;\n\n // Sanity-check before anyone feeds it to sandbox-exec.\n if (!/^\\(version 1\\)/m.test(text)) {\n throw new Error('generated sandbox profile is missing \"(version 1)\"');\n }\n return text;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-Dyp_hW97.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\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(config: Config, projectDir: string = process.cwd()): 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. */\nfunction 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 'DISABLE_AUTOUPDATER=1',\n 'NPM_CONFIG_USERCONFIG=/dev/null',\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 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 = process.cwd();\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 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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"}