Skip to content
Draft
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
8 changes: 7 additions & 1 deletion actors/runner/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@ RUN apk add --no-cache \
build-base \
wget ca-certificates \
zip unzip \
github-cli \
&& ln -sf /usr/bin/python3 /usr/bin/python

# Silence the apify-cli "OS keyring unavailable" warning on headless Alpine —
# there's no gnome-keyring / kwallet here, so credential lookup falls back to
# the file-backed store on every login. The env var makes that fallback silent.
ENV APIFY_DISABLE_KEYRING=1

# Claude Code CLI
RUN curl -fsSL https://claude.ai/install.sh | bash \
&& cp /root/.local/bin/claude /usr/local/bin/claude \
Expand All @@ -39,7 +45,7 @@ RUN curl -fsSL https://opencode.ai/install | bash \
RUN npm install -g @openai/codex apify-cli

# Verify all CLIs are available
RUN claude --version && codex --version && opencode --version && apify --version
RUN claude --version && codex --version && opencode --version && apify --version && gh --version

# Install runtime deps as root (npm needs write access to node_modules)
COPY package*.json ./
Expand Down
8 changes: 8 additions & 0 deletions shared/src/__tests__/apify-env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,12 @@ describe('buildChildEnv', () => {
expect(APIFY_RUNTIME_KEYS_TO_STRIP).toContain('APIFY_DEFAULT_DATASET_ID');
expect(APIFY_RUNTIME_KEYS_TO_STRIP).toContain('APIFY_IS_AT_HOME');
});

it('strips NODE_ENV so scaffolded projects install devDependencies as-usual', () => {
// apify/actor-node sets NODE_ENV=production; if that leaks into the agent's
// shell, `apify create` templates that rely on a devDep at runtime (e.g. tsx)
// fail because `npm install --omit=dev` drops it.
expect(buildChildEnv({ NODE_ENV: 'production' }, '/tmp/ws').NODE_ENV).toBeUndefined();
expect(APIFY_RUNTIME_KEYS_TO_STRIP).toContain('NODE_ENV');
});
});
9 changes: 9 additions & 0 deletions shared/src/agents/apify-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export const APIFY_RUNTIME_KEYS_TO_STRIP = [
'ACTOR_EVENTS_WEBSOCKET_URL', 'APIFY_ACTOR_EVENTS_WS_URL',
'APIFY_TIMEOUT_AT',
'APIFY_PROXY_PASSWORD',
// NODE_ENV is set to `production` by the apify/actor-node base image so the
// runner's own `npm install` skips devDependencies. When it leaks into the
// agent's subprocess, any scaffolded project the agent runs there inherits
// it too — so `apify create foo -t ts-empty && cd foo && apify run` fails
// with `sh: tsx: not found` because `npm install --omit=dev` drops `tsx`,
// even though the template lists it as a devDependency it needs at runtime.
// Stripping it here restores the "fresh dev machine" expectation that
// scaffolded templates are built against.
'NODE_ENV',
] as const;

/**
Expand Down
6 changes: 3 additions & 3 deletions shared/src/init-presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ export function runInitPreset(ctx: InitContext): InitResult {

case 'cli_native': {
const script = `
which gh >/dev/null 2>&1 || echo "gh not found (install with: brew install gh)"
which gh >/dev/null 2>&1 || echo "gh not found (install with: apk add github-cli / apt-get install gh / brew install gh)"
which apify >/dev/null 2>&1 || echo "apify not found (install with: npm i -g apify-cli)"
`;
const result = runScript(script, ctx.workDir, 'cli_native');
Expand Down Expand Up @@ -390,7 +390,7 @@ export function runInitPreset(ctx: InitContext): InitResult {
// (which would imply the agent bypassed the CLI).
const script = `
which apify >/dev/null 2>&1 || echo "apify not found (install with: npm i -g apify-cli)"
which gh >/dev/null 2>&1 || echo "gh not found (install with: brew install gh)"
which gh >/dev/null 2>&1 || echo "gh not found (install with: apk add github-cli / apt-get install gh / brew install gh)"
`;
const result = runScript(script, ctx.workDir, 'cli_only');
log.push(`cli_only: ${result.output}`);
Expand Down Expand Up @@ -456,7 +456,7 @@ export function runInitPreset(ctx: InitContext): InitResult {
// it would normally have, with visibility into what's available.
const script = `
which apify >/dev/null 2>&1 || echo "apify CLI not found (install with: npm i -g apify-cli)"
which gh >/dev/null 2>&1 || echo "gh not found (install with: brew install gh)"
which gh >/dev/null 2>&1 || echo "gh not found (install with: apk add github-cli / apt-get install gh / brew install gh)"
which curl >/dev/null 2>&1 || echo "curl not found (required for REST API calls)"
which jq >/dev/null 2>&1 || echo "jq not found (recommended for parsing API responses)"
`;
Expand Down
Loading