@bakers-build/addon-codex 0.5.1-next.776 → 0.5.1-next.808

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.
@@ -27,7 +27,7 @@ export declare class CodexAgent implements BbAgent {
27
27
  /** The launch flags a security mode owns (`docs/addons/codex.md`). */
28
28
  private securityFlags;
29
29
  private userMcpServers;
30
- launchCommand(prompt: string, _run?: AgentRunIdentity): string;
30
+ launchCommand(prompt: string, _run?: AgentRunIdentity, workspacePath?: string): string;
31
31
  getRunLog(worktreePath: string, run?: AgentRunIdentity): Promise<string>;
32
32
  parseFootprint(log: string): AgentFootprint;
33
33
  /** Codex brings its own sandbox runner; a missing binary fails at launch as before. */
package/dist/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { spawnSync } from 'node:child_process';
1
2
  import { readFileSync } from 'node:fs';
2
3
  import { readdir, readFile, stat } from 'node:fs/promises';
3
4
  import { homedir } from 'node:os';
@@ -127,7 +128,7 @@ export class CodexAgent {
127
128
  }
128
129
  }
129
130
  /** The launch flags a security mode owns (`docs/addons/codex.md`). */
130
- securityFlags() {
131
+ securityFlags(workspacePath) {
131
132
  const { mode, sandbox, config } = this.security;
132
133
  if (mode === 'system')
133
134
  return [];
@@ -145,18 +146,45 @@ export class CodexAgent {
145
146
  ]);
146
147
  if (mode === 'custom')
147
148
  return pairs(Object.entries(config ?? {}));
149
+ const gitDirs = new Set();
150
+ for (const option of ['--git-dir', '--git-common-dir']) {
151
+ const git = spawnSync('git', ['-C', workspacePath, 'rev-parse', '--path-format=absolute', option], { encoding: 'utf8', env: { ...process.env, LC_ALL: 'C' } });
152
+ if (git.error)
153
+ throw git.error;
154
+ if (git.status !== 0) {
155
+ if (git.stderr.includes('not a git repository'))
156
+ break;
157
+ throw new Error(`Cannot resolve Codex workspace Git directories: ${git.stderr.trim()}`);
158
+ }
159
+ gitDirs.add(git.stdout.replace(/\r?\n$/, ''));
160
+ }
161
+ const roots = sandbox.allow_write.map((dir) => `${JSON.stringify(dir.startsWith('~/') ? join(this.home, dir.slice(2)) : dir)} = true`);
162
+ // Filesystem overrides replace inherited entries, so retain workspace protections explicitly.
163
+ const filesystem = [
164
+ '":workspace_roots" = { ".git" = "read", ".agents" = "read", ".codex" = "read", ".aws" = "read" }',
165
+ ...[...gitDirs].flatMap((dir) => [
166
+ `${JSON.stringify(dir)} = "write"`,
167
+ // Unsandboxed Git later runs config/hooks code, or follows these redirects to it.
168
+ ...[
169
+ 'config',
170
+ 'config.worktree',
171
+ 'hooks',
172
+ 'commondir',
173
+ 'gitdir',
174
+ 'modules',
175
+ 'worktrees',
176
+ ].map((name) => `${JSON.stringify(join(dir, name))} = "read"`),
177
+ ]),
178
+ ];
179
+ const profile = `{ extends = ":workspace", filesystem = { ${filesystem.join(', ')} }, workspace_roots = { ${roots.join(', ')} }, network = { enabled = ${sandbox.network.length > 0} } }`;
148
180
  const flags = [
149
- '--sandbox',
150
- 'workspace-write',
151
181
  '-a',
152
182
  'never',
153
- ...pairs([
154
- ['sandbox_workspace_write.network_access', sandbox.network.length > 0],
155
- ]),
183
+ '-c',
184
+ 'default_permissions="bakers"',
185
+ '-c',
186
+ `permissions.bakers=${profile}`,
156
187
  ];
157
- for (const dir of sandbox.allow_write) {
158
- flags.push('--add-dir', dir.startsWith('~/') ? join(this.home, dir.slice(2)) : dir);
159
- }
160
188
  for (const id of this.userMcpServers()) {
161
189
  if (!Object.hasOwn(sandbox.mcp_servers, id)) {
162
190
  flags.push(...pairs([[`mcp_servers.${id}.enabled`, false]]));
@@ -175,10 +203,10 @@ export class CodexAgent {
175
203
  }
176
204
  return codexMcpServerIds(toml);
177
205
  }
178
- launchCommand(prompt, _run) {
206
+ launchCommand(prompt, _run, workspacePath = process.cwd()) {
179
207
  // Quote at assembly; a plain word has nothing for the shell to expand.
180
208
  const word = (t) => (/^[\w./=-]+$/.test(t) ? t : shellQuote(t));
181
- const parts = ['codex', ...this.securityFlags().map(word)];
209
+ const parts = ['codex', ...this.securityFlags(workspacePath).map(word)];
182
210
  if (this.model !== undefined && !this.overrides.model) {
183
211
  parts.push('--model', shellQuote(this.model));
184
212
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bakers-build/addon-codex",
3
- "version": "0.5.1-next.776",
3
+ "version": "0.5.1-next.808",
4
4
  "description": "bakers.build agent plugin for the Codex CLI.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,7 +20,7 @@
20
20
  "directory": "bakers-cli/addons/codex"
21
21
  },
22
22
  "peerDependencies": {
23
- "@bakers-build/conductor": "^0.5.1-next.776",
24
- "@bakers-build/core": "^0.5.1-next.776"
23
+ "@bakers-build/conductor": "^0.5.1-next.808",
24
+ "@bakers-build/core": "^0.5.1-next.808"
25
25
  }
26
26
  }