@cat-factory/executor-harness 1.50.0 → 1.50.2

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.
@@ -39,7 +39,8 @@ function attributeCumulativeUsage(calls, usage) {
39
39
  * system-prompt flag — the caller prepends the composed system prompt to it so
40
40
  * the role + best-practice context is not lost.
41
41
  */
42
- function streamCli(command, args, prompt, opts, env, secrets, onEvent) {
42
+ function streamCli(cli, prompt, opts, env, secrets, onEvent) {
43
+ const { command, args } = cli;
43
44
  return new Promise((resolve, reject) => {
44
45
  if (opts.signal?.aborted) {
45
46
  reject(new Error(`${command} aborted before start`));
@@ -271,22 +272,25 @@ export async function runClaudeCode(opts) {
271
272
  : { CLAUDE_CODE_OAUTH_TOKEN: opts.subscriptionToken }),
272
273
  };
273
274
  try {
274
- const { stderrTail } = await streamCli('claude', [
275
- '-p',
276
- '--output-format',
277
- 'stream-json',
278
- '--verbose',
279
- // The per-run container IS the sandbox, and the run is fully headless (no one
280
- // to approve a tool call) — so bypass permissions entirely. `acceptEdits`
281
- // would auto-accept file edits but still gate Bash, which in `-p` mode is then
282
- // denied, leaving the agent unable to run builds/tests/git to verify its work.
283
- '--permission-mode',
284
- 'bypassPermissions',
285
- '--model',
286
- opts.model,
287
- '--append-system-prompt',
288
- opts.systemPrompt,
289
- ], opts.userPrompt, opts, env, opts.subscriptionToken ? secretsToRedact(opts.subscriptionToken) : [], onEvent);
275
+ const { stderrTail } = await streamCli({
276
+ command: 'claude',
277
+ args: [
278
+ '-p',
279
+ '--output-format',
280
+ 'stream-json',
281
+ '--verbose',
282
+ // The per-run container IS the sandbox, and the run is fully headless (no one
283
+ // to approve a tool call) so bypass permissions entirely. `acceptEdits`
284
+ // would auto-accept file edits but still gate Bash, which in `-p` mode is then
285
+ // denied, leaving the agent unable to run builds/tests/git to verify its work.
286
+ '--permission-mode',
287
+ 'bypassPermissions',
288
+ '--model',
289
+ opts.model,
290
+ '--append-system-prompt',
291
+ opts.systemPrompt,
292
+ ],
293
+ }, opts.userPrompt, opts, env, opts.subscriptionToken ? secretsToRedact(opts.subscriptionToken) : [], onEvent);
290
294
  attributeCumulativeUsage(calls, usage);
291
295
  return {
292
296
  summary,
@@ -472,17 +476,20 @@ export async function runCodex(opts) {
472
476
  }
473
477
  };
474
478
  try {
475
- const { stderrTail } = await streamCli('codex', [
476
- 'exec',
477
- '--json',
478
- '--skip-git-repo-check',
479
- // The per-run container IS the sandbox; let Codex write files and reach the
480
- // vendor unrestricted, with no approval prompts (the run is headless).
481
- '--dangerously-bypass-approvals-and-sandbox',
482
- '--model',
483
- opts.model,
484
- '-',
485
- ], prompt, opts, codexHome ? { CODEX_HOME: codexHome } : {}, opts.subscriptionToken ? secretsToRedact(opts.subscriptionToken) : [], onEvent);
479
+ const { stderrTail } = await streamCli({
480
+ command: 'codex',
481
+ args: [
482
+ 'exec',
483
+ '--json',
484
+ '--skip-git-repo-check',
485
+ // The per-run container IS the sandbox; let Codex write files and reach the
486
+ // vendor unrestricted, with no approval prompts (the run is headless).
487
+ '--dangerously-bypass-approvals-and-sandbox',
488
+ '--model',
489
+ opts.model,
490
+ '-',
491
+ ],
492
+ }, prompt, opts, codexHome ? { CODEX_HOME: codexHome } : {}, opts.subscriptionToken ? secretsToRedact(opts.subscriptionToken) : [], onEvent);
486
493
  // Fallback for a CLI/version that never emits per-turn `last_token_usage`: record a
487
494
  // single call from the cumulative total + final text so the run is still observable.
488
495
  if (calls.length === 0 && (usage || summary)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/executor-harness",
3
- "version": "1.50.0",
3
+ "version": "1.50.2",
4
4
  "description": "Container payload: a thin TypeScript wrapper that runs the Pi coding agent against a cloned repo and opens a PR. Runs in the Cloudflare Container (and, in local native mode, as a host process); carries no secrets.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,8 +26,8 @@
26
26
  "hono": "^4.12.30",
27
27
  "typescript": "7.0.2",
28
28
  "vitest": "^4.1.10",
29
- "@cat-factory/server": "0.138.7",
30
- "@cat-factory/spend": "0.12.62"
29
+ "@cat-factory/server": "0.138.11",
30
+ "@cat-factory/spend": "0.12.63"
31
31
  },
32
32
  "scripts": {
33
33
  "build": "tsc -p tsconfig.json",
@@ -118,14 +118,14 @@ function attributeCumulativeUsage(
118
118
  * the role + best-practice context is not lost.
119
119
  */
120
120
  function streamCli(
121
- command: string,
122
- args: string[],
121
+ cli: { command: string; args: string[] },
123
122
  prompt: string,
124
123
  opts: SubscriptionRunOptions,
125
124
  env: Record<string, string>,
126
125
  secrets: string[],
127
126
  onEvent: (event: Record<string, unknown>) => void,
128
127
  ): Promise<{ stderrTail: string }> {
128
+ const { command, args } = cli
129
129
  return new Promise((resolve, reject) => {
130
130
  if (opts.signal?.aborted) {
131
131
  reject(new Error(`${command} aborted before start`))
@@ -374,23 +374,25 @@ export async function runClaudeCode(opts: SubscriptionRunOptions): Promise<PiRun
374
374
 
375
375
  try {
376
376
  const { stderrTail } = await streamCli(
377
- 'claude',
378
- [
379
- '-p',
380
- '--output-format',
381
- 'stream-json',
382
- '--verbose',
383
- // The per-run container IS the sandbox, and the run is fully headless (no one
384
- // to approve a tool call) so bypass permissions entirely. `acceptEdits`
385
- // would auto-accept file edits but still gate Bash, which in `-p` mode is then
386
- // denied, leaving the agent unable to run builds/tests/git to verify its work.
387
- '--permission-mode',
388
- 'bypassPermissions',
389
- '--model',
390
- opts.model,
391
- '--append-system-prompt',
392
- opts.systemPrompt,
393
- ],
377
+ {
378
+ command: 'claude',
379
+ args: [
380
+ '-p',
381
+ '--output-format',
382
+ 'stream-json',
383
+ '--verbose',
384
+ // The per-run container IS the sandbox, and the run is fully headless (no one
385
+ // to approve a tool call) so bypass permissions entirely. `acceptEdits`
386
+ // would auto-accept file edits but still gate Bash, which in `-p` mode is then
387
+ // denied, leaving the agent unable to run builds/tests/git to verify its work.
388
+ '--permission-mode',
389
+ 'bypassPermissions',
390
+ '--model',
391
+ opts.model,
392
+ '--append-system-prompt',
393
+ opts.systemPrompt,
394
+ ],
395
+ },
394
396
  opts.userPrompt,
395
397
  opts,
396
398
  env,
@@ -594,18 +596,20 @@ export async function runCodex(opts: SubscriptionRunOptions): Promise<PiRunOutco
594
596
 
595
597
  try {
596
598
  const { stderrTail } = await streamCli(
597
- 'codex',
598
- [
599
- 'exec',
600
- '--json',
601
- '--skip-git-repo-check',
602
- // The per-run container IS the sandbox; let Codex write files and reach the
603
- // vendor unrestricted, with no approval prompts (the run is headless).
604
- '--dangerously-bypass-approvals-and-sandbox',
605
- '--model',
606
- opts.model,
607
- '-',
608
- ],
599
+ {
600
+ command: 'codex',
601
+ args: [
602
+ 'exec',
603
+ '--json',
604
+ '--skip-git-repo-check',
605
+ // The per-run container IS the sandbox; let Codex write files and reach the
606
+ // vendor unrestricted, with no approval prompts (the run is headless).
607
+ '--dangerously-bypass-approvals-and-sandbox',
608
+ '--model',
609
+ opts.model,
610
+ '-',
611
+ ],
612
+ },
609
613
  prompt,
610
614
  opts,
611
615
  codexHome ? { CODEX_HOME: codexHome } : {},