@workos/quickstudy 0.2.0 → 0.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workos/quickstudy",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "An open-source, company-agnostic eval harness for measuring whether coding agents can complete real integration tasks, across an agent x feature x framework x surface matrix.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ export const EMBEDDED_BUILD_INFO: {
9
9
  // (the `x-release-please-version` marker anchors the replacement). It is
10
10
  // restored as-is after a binary build (scripts/build-binary.ts), so the
11
11
  // committed source `--version` stays in lockstep with package.json.
12
- version: "0.2.0", // x-release-please-version
12
+ version: "0.2.1", // x-release-please-version
13
13
  revision: null,
14
14
  dirty: null,
15
15
  sourceHash: null,
@@ -246,8 +246,13 @@ export async function createAttemptContainer(opts: CreateAttemptContainerOptions
246
246
  execInWorkspace: async (cmd, execOpts = {}) => {
247
247
  const result = await runDocker(["exec", "-w", CONTAINER_WORKSPACE, id, ...cmd], execOpts);
248
248
  // Killing only the Docker client leaves the exec process alive in the
249
- // daemon. Stop the whole attempt on timeout, including descendants.
250
- if (result.timedOut) await runDocker(["kill", id], { timeoutMs: 10_000 });
249
+ // daemon. Stop the whole attempt on timeout, including descendants —
250
+ // then restart PID 1 (`sleep infinity`) so the dead attempt's workspace
251
+ // stays exec-able for the diff. Descendants do not come back with it.
252
+ if (result.timedOut) {
253
+ await runDocker(["kill", id], { timeoutMs: 10_000 });
254
+ await runDocker(["start", id], { timeoutMs: 10_000 });
255
+ }
251
256
  return result;
252
257
  },
253
258
  writeFile: async (path, content) => {
@@ -826,8 +826,26 @@ async function runContainerAttemptV3(
826
826
  );
827
827
  }
828
828
  }
829
+ // `git add -A` stages new files so the diff captures them; diffing
830
+ // the recorded baseline SHA (not HEAD) also captures any commits the
831
+ // agent made itself.
832
+ const captureDiff = async (): Promise<void> => {
833
+ if (baselineSha === undefined) return;
834
+ await mustExec(container, ["git", "add", "-A"]);
835
+ const diff = (await mustExec(container, ["git", "diff", baselineSha])).stdout;
836
+ persisted.diffRef = await artifacts.writeDiff(runId, attemptId, redactSecrets(diff, secretEnv));
837
+ };
838
+ if (agentResult.timedOut || agentResult.exitCode !== 0) {
839
+ // The workspace is evidence of what the agent got done before it
840
+ // died; a failed capture must not mask the attempt's own outcome.
841
+ try {
842
+ await captureDiff();
843
+ } catch (err) {
844
+ (options.log ?? console.log)(`attempt ${attemptId}: diff unavailable after failure: ${err instanceof Error ? err.message : String(err)}`);
845
+ }
846
+ }
829
847
  if (agentResult.timedOut) {
830
- await artifacts.writeError(runId, attemptId, `attempt timed out after ${args.attemptTimeoutMs}ms — container removed`);
848
+ await artifacts.writeError(runId, attemptId, `attempt timed out after ${args.attemptTimeoutMs}ms — container killed`);
831
849
  return { status: "incomplete", error: `attempt timed out after ${args.attemptTimeoutMs}ms` };
832
850
  }
833
851
  if (agentResult.exitCode !== 0) {
@@ -836,14 +854,7 @@ async function runContainerAttemptV3(
836
854
  return { status: "error", error: `agent command exited ${agentResult.exitCode}` };
837
855
  }
838
856
 
839
- if (baselineSha !== undefined) {
840
- // `git add -A` stages new files so the diff captures them; diffing
841
- // the recorded baseline SHA (not HEAD) also captures any commits
842
- // the agent made itself.
843
- await mustExec(container, ["git", "add", "-A"]);
844
- const diff = (await mustExec(container, ["git", "diff", baselineSha])).stdout;
845
- persisted.diffRef = await artifacts.writeDiff(runId, attemptId, redactSecrets(diff, secretEnv));
846
- }
857
+ await captureDiff();
847
858
 
848
859
  // Export the workspace BEFORE scoring, with the container still alive:
849
860
  // file checks read the export, ctx.exec reaches into the live sandbox.