Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/local/auto-fix-loop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,34 @@ describe('runWithAutoFix', () => {
expect(repair?.content).toContain('MISSING_ENV_VAR:');
});

// Regression: assertRickyWorkflowEnv used to throw at module-load time
// unconditionally, before the SDK had a chance to honour --start-from.
// That made resuming with --start-from impossible if the resumed step
// didn't actually need the missing env var (the upstream-only step did,
// but it was being skipped). The injected helper now warns-and-continues
// when process.env.START_FROM is set so resumed steps can run and any
// step that genuinely needs a missing value still fails with its own
// signal at the point of use.
it('injects an env-assert helper that honors START_FROM for --start-from resumes', () => {
const repair = repairWorkflowDeterministically({
artifactPath: 'workflows/generated/foo.ts',
artifactContent: workflowContent(),
evidence: missingEnvEvidence(),
response: blockerResponse('MISSING_ENV_VAR', 'run-1', 'runtime-launch'),
});

expect(repair?.applied).toBe(true);
// Resume signal acknowledged.
expect(repair?.content).toContain('process.env.START_FROM');
// Warn-and-continue path uses console.warn rather than throwing so the
// SDK can proceed to the resumed step.
expect(repair?.content).toMatch(/console\.warn\([^)]*Skipping env-var assertion/);
expect(repair?.content).toMatch(/--start-from active/);
// The non-resume path still throws fast — preserves the original
// contract for first-run invocations.
expect(repair?.content).toContain('throw new Error(`MISSING_ENV_VAR:');
});

// Regression: when a master-rendered workflow embeds a `node --input-type=module`
// HEREDOC inside a .step({ command: ... }) string, the embedded shell text
// contains the literal substring `from 'node:fs'`. The previous import-detection
Expand Down
21 changes: 17 additions & 4 deletions src/local/auto-fix-loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,9 +822,19 @@ function loadRickyWorkflowEnv(cwd = process.cwd()) {

function assertRickyWorkflowEnv(names: string[]): void {
const missing = names.filter((name) => !process.env[name]);
if (missing.length > 0) {
throw new Error(\`MISSING_ENV_VAR: \${missing.join(', ')}. Add missing values to .env.local or export them before rerunning.\`);
if (missing.length === 0) return;
// When the workflow is being resumed via --start-from, the SDK sets
// process.env.START_FROM. Skipped upstream steps may have been the
// ones that needed these env vars; the resumed steps may not. Warn
// instead of failing fast so the resume can proceed and any step that
// actually needs a missing value will fail naturally with its own
// signal. Without this, --start-from on a workflow whose missing env
// var isn't in the resumed step's path is unrecoverable from the CLI.
if (process.env.START_FROM) {
console.warn(\`[ricky] Skipping env-var assertion (--start-from active): missing \${missing.join(', ')}. Resumed steps that actually need these will fail with their own error.\`);
return;
}
throw new Error(\`MISSING_ENV_VAR: \${missing.join(', ')}. Add missing values to .env.local or export them before rerunning.\`);
}

function unquoteRickyWorkflowEnvValue(value: string): string {
Expand All @@ -839,9 +849,12 @@ function unquoteRickyWorkflowEnvValue(value: string): string {
function rickyWorkflowEnvAssertSource(): string {
return `function assertRickyWorkflowEnv(names: string[]): void {
const missing = names.filter((name) => !process.env[name]);
if (missing.length > 0) {
throw new Error(\`MISSING_ENV_VAR: \${missing.join(', ')}. Add missing values to .env.local or export them before rerunning.\`);
if (missing.length === 0) return;
if (process.env.START_FROM) {
console.warn(\`[ricky] Skipping env-var assertion (--start-from active): missing \${missing.join(', ')}. Resumed steps that actually need these will fail with their own error.\`);
return;
}
throw new Error(\`MISSING_ENV_VAR: \${missing.join(', ')}. Add missing values to .env.local or export them before rerunning.\`);
}`;
}

Expand Down
Loading