diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..2c47fad2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,33 @@ +# CLAUDE.md + +Guidance for Claude Code working in this repository. Humans should read [README.md](./README.md) and [CONTRIBUTING.md](./CONTRIBUTING.md) first. + +## Entry points + +- `apify` CLI — `src/entrypoints/apify.ts` +- `actor` CLI — `src/entrypoints/actor.ts` + +## Before you push + +Run `yarn lint && yarn format && yarn build && yarn test:local` before pushing. Run `yarn test:api` too if you changed anything that touches the Apify API. + +If you modified a command's flags, args, description, or added/removed a command, also run `yarn update-docs` and commit the regenerated `docs/` output. + +## Code conventions + +- Package manager: **Yarn 4** (via Corepack). Do not use npm. +- Use `.js` import specifiers for local files (e.g. `import { foo } from './foo.js'`). The `.ts` source resolves at build time. +- Commands extend `ApifyCommand` from `src/lib/command-framework/apify-command.ts`. Follow the pattern of existing commands: `static override name`, `static override description`, `static override flags/args`, and an `async run()` method. +- New commands must be registered in `src/commands/_register.ts` (or the parent `_index.ts` for subcommands). +- Do not add docstrings, comments, or type annotations to code you did not change. Keep diffs tight. + +## Testing + +- Tests use **Vitest**. See [CONTRIBUTING.md](./CONTRIBUTING.md#writing-tests) for `useAuthSetup` and `useTempPath` hook usage. +- API tests must include `[api]` in the test name and live in `test/api/`. +- Always `import process from 'node:process'` in command/lib code — never use `globalThis.process`. This is required for test cwd mocks to work. + +## Things to avoid + +- Do not use `--no-verify` to skip git hooks. Fix the underlying issue. +- Do not edit `docs/` by hand — it is generated by `yarn update-docs`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2ea439d1..ec6b1ffa0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,99 +1,124 @@ -# Contributing to apify-cli +# Contributing to Apify CLI -## Dev mode +Thanks for your interest in contributing! This guide covers local setup, code style, tests, and the PR process. For a high-level tour of the repo aimed at AI coding assistants, see [CLAUDE.md](./CLAUDE.md). -You can run `yarn dev:apify` to run the CLI in development mode. This will use the local version of the CLI instead of the one installed globally. +## Prerequisites -## Tests +- **Node.js** 22 or higher +- **Yarn 4** (enabled via Corepack — do not install Yarn globally with npm) +- **Bun** ≥ 1.2.5 (optional; only needed if you want to build the standalone bundles locally) +- An [Apify account](https://console.apify.com/) and an API token if you want to run the API test suite -Tests are implemented using the [Vitest](https://vitest.dev/) framework. -You need to have Apify account to test all apify-cli features. +Enable Corepack once per machine: -Then you can run tests with commands in repository root directory: +```bash +corepack enable +``` -1. Install all dependencies: - `yarn` +## Local setup -2. Run tests using credentials of the 'apify-test' user: - `TEST_USER_TOKEN= yarn test:all` +```bash +git clone https://github.com/apify/apify-cli.git +cd apify-cli +yarn +yarn build +``` -## Publish new version +Run the CLI straight from source in dev mode (no global install required): -Only users with access to [apify-cli package](https://www.npmjs.com/package/apify-cli) can publish new version. +```bash +yarn dev:apify --version +yarn dev:apify create my-actor +``` -Release of new versions is managed by GitHub Actions. On pushes to the master branch, prerelease versions are automatically produced. Latest releases are triggered manually through the GitHub release tool. After creating a release there, Actions will automatically produce the latest version of the package. +`yarn dev:actor` does the same for the in-Actor `actor` binary. -1. Manually increment version in `package.json` +## Code style -2. GitHub Actions build is triggered by a push to `master` (typically a merge of a PR). +The repo uses three tools, wired together via a pre-commit hook (`husky` + `lint-staged`): -3. To trigger the latest release, go to the GitHub release tool (select `releases` under `<> Code`). There, draft a new release, fill the form and hit `Publish release`. Actions will automatically release the latest version of the package. +- **Biome** — formats JavaScript / TypeScript. Config: `biome.json`. +- **ESLint** — lints JavaScript / TypeScript using `@apify/eslint-config`. Config: `eslint.config.mjs`. +- **Prettier** — formats Markdown and YAML. Config: inherited defaults. -## Writing tests +Run checks manually: -In `test/__setup__/hooks` we have a collection of hooks that you can use while writing tests to set up the testing environment to be usable when running tests in parallel (especially useful for tests that require authenticating into an Apify account). +```bash +yarn lint # ESLint +yarn format # Biome + Prettier (check only) +yarn lint:fix # Auto-fix ESLint issues +yarn format:fix # Auto-format with Biome + Prettier +``` -### `useAuthSetup` +The pre-commit hook runs these on staged files automatically. Do not bypass it with `--no-verify` — if a hook fails, fix the underlying issue and create a new commit. -Use this hook at the start of your test file to mark the entire suite as require-ing a separated authentication setup. By default, this will recreate the authentication setup per test in your suite, but you can disable that by passing in `{ perTest: false }` in the call to `useAuthSetup`.` +## Before opening a PR -If you're writing a test case or file that relies on API interactions, make sure it either goes in the `test/api` folder, and that it has a `[api]` reference in the name of the test case (usually at the start). -If your test file also mixes local tests, always add `[api]` for test cases that need the API. They will automatically be skipped for local tests. +Run the full local gauntlet before pushing: -#### Example usage +1. `yarn lint` +2. `yarn format` +3. `yarn build` +4. `yarn test:local` (and `yarn test:api` if relevant — see below) -```typescript -import { useAuthSetup } from "./__setup__/hooks"; +If you added, removed, or changed a command's signature, regenerate the reference docs: -useAuthSetup(); -// Alternatively, if this suite requires the authentication to persist across all tests -useAuthSetup({ perTest: false }); +```bash +yarn update-docs ``` -### `useTempPath` +Commit the updated `docs/` output alongside your change. -This hook should always be used when working with commands that alter the file system. This hook: +## Tests -- creates your temporary directory with the name you provided -- provides calls for before and after all tests to setup and clean up the temporary directory -- supports mocking the process cwd to the temporary directory so you can run commands and test their behavior. +Tests use [Vitest](https://vitest.dev/). They fall into four categories: -**Important note about the cwd mocking**: when you use this hook and tell it to mock the cwd, you need to ensure these following things **always** happen: +| Script | What it runs | When to run | +| -------------------- | ------------------------------------------------------------------------ | -------------------------------------------------- | +| `yarn test:local` | Everything except tests named `[api]` and everything outside `test/api/` | Always, on every change | +| `yarn test:api` | Only tests tagged `[api]` — hits the real Apify API | When you touch API-facing code | +| `yarn test:python` | Tests tagged `[python]` — exercises Python Actor templates | When you touch Python template / integration code | +| `yarn test:cucumber` | Cucumber features in `features/` | When you touch anything covered by a `.feature.md` | +| `yarn test:all` | `test:local` then `test:api` | Full pre-release check | -- You import `process` from `node:process` in your command or file you want to test with the mocked cwd. You do not use `globalThis.process` at all! -- You import the files that may rely on the mocked cwd AFTER you call `useTempPath` in your test file, by using `await import()` instead of `import x from '..';` +API tests need a token: -It also comes with several options: +```bash +TEST_USER_TOKEN= yarn test:api +``` -- `create`: defaulted to `true`, it decides if the temporary directory should be created or not in the beforeAll hook. -- `remove`: defaulted to `true`, it decides if the temporary directory should be removed or not in the afterAll hook. -- `cwd`: defaulted to `false`, it decides if the process.cwd should be mocked to the temporary directory or not. -- `cwdParent`: defaulted to `false`, it decides whether the initial value of the mocked process.cwd will point to the parent directory of the temporary directory or the actual temporary directory. +Use a dedicated test account — API tests create and destroy Actors, datasets, and other resources. -This hook also returns several values in an object: +## Writing tests -- `tmpPath`: the full path to the temporary directory that was requested -- `joinPath`: a utility function similar to `path.join` that lets you work with paths in the temporary directory -- `beforeAllCalls`: a function you should manually call in your `beforeAll` hook to set up the temporary directory as well as the used cwd mock -- `afterAllCalls`: a function you should manually call in your `afterAll` hook to clean up the temporary directory -- `toggleCwdBetweenFullAndParentPath`: a function you can call to toggle the cwd mock between the full path to the temporary directory and the parent directory of the temporary directory +Shared helpers live in `test/__setup__/hooks/`. Two of them show up in most new tests: -#### Example usage (creates an actor, then pushes it, then calls it) +### `useAuthSetup` -> This example assumes you've also handled logging in. +Isolates Apify authentication state per suite (or per test). Use it in any file that logs in, pushes, pulls, or otherwise touches `~/.apify`. By default it recreates the auth setup per test; pass `{ perTest: false }` to share one setup across the suite. ```typescript -import { useTempPath } from "./__setup__/hooks"; -import { writeFile } from "node:fs/promises"; +import { useAuthSetup } from "./__setup__/hooks"; -const ACTOR_NAME = "owo"; +useAuthSetup(); +// or: useAuthSetup({ perTest: false }); +``` + +API-dependent test cases must have `[api]` in the test name and live in `test/api/`. Files outside `test/api/` may mix local and `[api]` tests — the `test:local` script skips the `[api]` ones by name. + +### `useTempPath` + +Creates (and cleans up) a temporary directory, and optionally mocks `process.cwd()` so commands run as if executed there. + +```typescript +import { useTempPath } from "./__setup__/hooks"; const { beforeAllCalls, afterAllCalls, joinPath, toggleCwdBetweenFullAndParentPath, -} = useTempPath(ACTOR_NAME, { +} = useTempPath("my-actor", { cwd: true, cwdParent: true, create: true, @@ -101,37 +126,43 @@ const { }); const { CreateCommand } = await import("../../src/commands/create.js"); -const { PushCommand } = await import("../../src/commands/push.js"); -const { CallCommand } = await import("../../src/commands/call.js"); +``` -beforeAll(async () => { - await beforeAllCalls(); +Options: - await CreateCommand.run( - [ACTOR_NAME, "--template", "project_empty", "--skip-dependency-install"], - import.meta.url, - ); +- `create` (default `true`) — create the temp directory in `beforeAll`. +- `remove` (default `true`) — remove it in `afterAll`. +- `cwd` (default `false`) — mock `process.cwd()` to point at the temp directory. +- `cwdParent` (default `false`) — start the mocked cwd at the parent of the temp directory. - const code = ` -import { Actor } from 'apify'; +Returned helpers: -Actor.main(async () => { - await Actor.setValue('OUTPUT', 'Hello world!'); - console.log('Done!'); -});`; +- `tmpPath` — absolute path of the temp directory. +- `joinPath(...segments)` — `path.join` rooted at `tmpPath`. +- `beforeAllCalls`, `afterAllCalls` — call these from your `beforeAll` / `afterAll`. +- `toggleCwdBetweenFullAndParentPath()` — flip the mocked cwd between the temp dir and its parent. - await writeFile(joinPath("main.js"), code); +**Important when using `cwd: true`:** in the code you are testing, always `import process from 'node:process'` (never `globalThis.process`), and dynamically `await import(...)` anything that reads cwd **after** `useTempPath` runs. - toggleCwdBetweenFullAndParentPath(); +### Running individual commands - await PushCommand.run(["--no-prompt"], import.meta.url); -}); +Use `testRunCommand` from the command framework to invoke CLI commands in tests — it bypasses the entry-point wrapper and gives you the parsed context directly. -afterAll(async () => { - await afterAllCalls(); -}); -``` +## Pull requests + +- Branch from `master`. Name branches descriptively (e.g. `fix/push-handles-empty-dir`, `feat/actors-search`). +- Write [Conventional Commit](https://www.conventionalcommits.org/) messages: `feat:`, `fix:`, `docs:`, `chore:`, `refactor:`, `test:`. The changelog generator (`git-cliff`) groups entries by prefix, so this matters. +- Keep PRs focused. Unrelated cleanup is easier to review in a separate PR. +- Include tests when you fix a bug or add behavior. +- Update `docs/` via `yarn update-docs` if you changed any command. + +Open PRs against `master`. Code owners are configured in [`.github/CODEOWNERS`](./.github/CODEOWNERS) and will be requested automatically. + +## Releases + +Releases are fully automated via GitHub Actions — **do not bump the version in `package.json` manually**. -### Running commands +- **Pre-releases (beta):** every push to `master` triggers `.github/workflows/pre_release.yaml`, which computes the next beta version, updates `CHANGELOG.md`, and publishes to npm under the `beta` tag. +- **Stable releases:** trigger the **Create a release** workflow (`.github/workflows/release.yaml`) manually from the GitHub Actions UI. It computes the next version (auto / patch / minor / major / custom), updates `CHANGELOG.md`, builds standalone bundles for Linux / macOS / Windows (x64 + ARM64), creates a GitHub release with the bundles attached, publishes to npm under `latest`, and opens a PR against the Homebrew formula. -Running commands in tests can be done by calling `testRunCommand` (imported from the command framework) +Only users with publish access to the [`apify-cli` npm package](https://www.npmjs.com/package/apify-cli) can trigger the stable release workflow. diff --git a/README.md b/README.md index 16abf2d82..740eb0158 100644 --- a/README.md +++ b/README.md @@ -1,283 +1,129 @@ -# Apify command-line interface (Apify CLI) +# Apify CLI [![NPM version](https://badge.fury.io/js/apify-cli.svg)](https://www.npmjs.com/package/apify-cli) [![GitHub workflow](https://github.com/apify/apify-cli/actions/workflows/check.yaml/badge.svg)](https://github.com/apify/apify-cli/actions/workflows/check.yaml) -Apify command-line interface (Apify CLI) helps you create, develop, build and run -[Apify Actors](https://www.apify.com/actors), -and manage the Apify cloud platform from any computer. +Apify CLI is the command-line tool for creating, developing, and deploying [Apify Actors](https://www.apify.com/actors), and for managing the Apify cloud platform from your terminal. -Apify Actors are cloud programs that can perform arbitrary web scraping, automation or data processing job. -They accept input, perform their job and generate output. -While you can develop Actors in an online IDE directly in the [Apify web application](https://console.apify.com/), -for complex projects it is more convenient to develop Actors locally on your computer -using Apify SDK -and only push the Actors to the Apify cloud during deployment. -This is where the Apify CLI comes in. +## Features -Note that Actors running on the Apify platform are executed in Docker containers, so with an appropriate `Dockerfile` -you can build your Actors in any programming language. -However, we recommend using JavaScript / Node.js, for which we provide most libraries and support. +- Create, develop, and deploy Apify Actors from your terminal +- Run Actors locally for development and testing, or in the Apify cloud +- Manage Actors, datasets, key-value stores, and request queues +- Manage secret environment variables used by your Actors +- Works with any programming language — Actors run as Docker containers on the platform -## Installation - -### Via bundles - -#### MacOS / Unix - -```bash -curl -fsSL https://apify.com/install-cli.sh | bash -``` - -#### Windows - -```powershell -irm https://apify.com/install-cli.ps1 | iex -``` - -### Via Homebrew +## Quick start -On macOS (or Linux), you can install the Apify CLI via the [Homebrew package manager](https://brew.sh). - -```bash -brew install apify-cli -``` +1. **Install the CLI** (macOS / Linux): -### Via NPM + ```bash + curl -fsSL https://apify.com/install-cli.sh | bash + ``` -First, make sure you have [Node.js](https://nodejs.org) version 22 or higher with NPM installed on your computer: + For Windows and other installation options, see [Installation](#installation). -```bash -node --version -npm --version -``` +2. **Log in** with your [Apify API token](https://console.apify.com/settings/integrations): -Install or upgrade Apify CLI by running: + ```bash + apify login + ``` -```bash -npm install -g apify-cli -``` - -Alternatively, you can use [fnm (Fast Node Manager)](https://github.com/Schniz/fnm) and install Apify CLI only into a selected user-level Node version without requiring root privileges: - -```bash -fnm install 22 -fnm use 22 -npm install -g apify-cli -``` - -Finally, verify that Apify CLI was installed correctly by running: - -```bash -apify --version -``` - -> You can also skip the manual global installation altogether and use `npx apify-cli` with all the following commands instead. - -## Basic usage - -The following examples demonstrate the basic usage of Apify CLI. - -### Create a new Actor from scratch - -```bash -apify create my-hello-world -``` +3. **Create, run, and deploy** your first Actor: -First, you will be prompted to select a template with the boilerplate for the Actor, to help you get started quickly. -The command will create a directory called `my-hello-world` that contains a Node.js project -for the Actor and a few configuration files. + ```bash + apify create # it will walk you through an interactive wizard + cd my-actor + apify run + apify push + ``` -> If you decided to skip the installation and go with `npx`, the command will be `npx apify-cli create my-hello-world`. - -### Create a new Actor from existing project - -```bash -cd ./my/awesome/project -apify init -``` - -This command will only set up local Actor development environment in an existing directory, -i.e. it will create the `.actor/actor.json` file and `apify_storage` directory. - -Before you can run your project locally using `apify run`, you have to set up the right start command in `package.json` under scripts.start. For example: - -```text -{ - ... - "scripts": { - "start": "node your_main_file.js", - }, - ... -} -``` - -You can find more information about by running `apify help run`. - -### Create a new Actor from Scrapy project - -If you want to run a Scrapy project on Apify platform, follow the [Scrapy integration guide](https://docs.apify.com/cli/docs/integrating-scrapy). +## Installation -### Run the Actor locally +### macOS / Linux (bundle, recommended) ```bash -cd my-hello-world -apify run +curl -fsSL https://apify.com/install-cli.sh | bash ``` -This command runs the Actor on your local machine. -Now's your chance to develop the logic - or magic :smirk: - -### Login with your Apify account +### macOS / Linux (Homebrew) ```bash -apify login +brew install apify-cli ``` -Before you can interact with the Apify cloud, you need to [create an Apify account](https://console.apify.com/) -and log in to it using the above command. You will be prompted for -your [Apify API token](https://console.apify.com/settings/integrations). -Note that the command will store the API token and other sensitive information to `~/.apify`. +### Windows -### Push the Actor to the Apify cloud - -```bash -apify push +```powershell +irm https://apify.com/install-cli.ps1 | iex ``` -This command uploads your project to the Apify cloud and builds an Actor from it. On the platform, Actor needs to be built before it can be run. +### npm (cross-platform) -### Run an Actor on the Apify cloud +Requires [Node.js](https://nodejs.org) 22 or higher: ```bash -apify call +npm install -g apify-cli ``` -Runs the Actor corresponding to the current directory on the Apify platform. +You can also run the CLI without a global install via `npx apify-cli `. -This command can also be used to run other Actors, for example: +Verify the installation: ```bash -apify call apify/hello-world -``` - -### So what's in this .actor/actor.json file? - -This file associates your local development project with an Actor on the Apify platform. -It contains information such as Actor name, version, build tag and environment variables. -Make sure you commit this file to the Git repository. - -For example, `.actor/actor.json` file can look as follows: - -```json -{ - "actorSpecification": 1, - "name": "name-of-my-scraper", - "version": "0.0", - "buildTag": "latest", - "environmentVariables": { - "MYSQL_USER": "my_username", - "MYSQL_PASSWORD": "@mySecretPassword" - }, - "dockerfile": "./Dockerfile", - "readme": "./ACTOR.md", - "input": "./input_schema.json", - "storages": { - "dataset": "./dataset_schema.json" - } -} +apify --version ``` -**`Dockerfile` field**\ -If you specify the path to your Docker file under the `dockerfile` field, this file will be used for Actor builds on the platform. If not specified, the system will look for Docker files at `.actor/Dockerfile` and `Dockerfile` in this order of preference. - -**`Readme` field** \ -If you specify the path to your readme file under the `readme` field, the readme at this path will be used on the platform. If not specified, readme at `.actor/README.md` and `README.md` will be used in this order of preference. +## Commands -**`Input` field**\ -You can embed your [input schema](https://docs.apify.com/actors/development/input-schema#specification-version-1) object directly in `actor.json` under `input` field. Alternatively, you can provide a path to a custom input schema. If not provided, the input schema at `.actor/INPUT_SCHEMA.json` and `INPUT_SCHEMA.json` is used in this order of preference. +The table below lists the most common commands. For the full reference, see the [command reference](https://docs.apify.com/cli/docs/reference). -**`Storages.dataset` field**\ -You can define the schema of the items in your dataset under the `storages.dataset` field. This can be either an embedded object or a path to a JSON schema file. You can read more about the schema of your Actor output [here](https://docs.apify.com/actors/development/output-schema#specification-version-1). +| Command | Description | +| --------------- | --------------------------------------------------------- | +| `apify create` | Create a new Actor project from a template | +| `apify init` | Initialize an existing project as an Actor | +| `apify run` | Run the Actor locally | +| `apify login` | Authenticate with the Apify platform | +| `apify logout` | Log out of the Apify platform | +| `apify push` | Deploy the Actor to the Apify cloud | +| `apify pull` | Pull an Actor from the cloud to your local machine | +| `apify call` | Run the Actor on the Apify cloud | +| `apify builds` | Manage Actor builds (`create`, `info`, `ls`, `log`, `rm`) | +| `apify secrets` | Manage secret environment variables | +| `apify help` | Show help for any command | -**Note on migration from deprecated config "apify.json"**\ -_Note that previously, Actor config was stored in the `apify.json` file that has been deprecated. You can find the (very slight) differences and migration info in [migration guidelines](https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md)._ +Actor configuration lives in `.actor/actor.json`. See the [Actor configuration docs](https://docs.apify.com/platform/actors/development/actor-definition/actor-json) for the full schema (name, version, build tag, environment variables, Dockerfile, input schema, storages). -## Environment variables +## Documentation -There are two options how you can set up environment variables for Actors. +- [Apify CLI documentation](https://docs.apify.com/cli) +- [Command reference](https://docs.apify.com/cli/docs/reference) +- [Actor development guide](https://docs.apify.com/platform/actors/development) +- [Apify platform documentation](https://docs.apify.com/platform) -### Set up environment variables in .actor/actor.json +## Telemetry -All keys from `env` will be set as environment variables into Apify platform after you push Actor to Apify. Current values on Apify will be overridden. +Apify CLI collects anonymous usage data to help us improve the tool and the Apify platform. See [Telemetry](https://docs.apify.com/cli/docs/telemetry) for details on what is collected. -```json -{ - "actorSpecification": 1, - "name": "dataset-to-mysql", - "version": "0.1", - "buildTag": "latest", - "environmentVariables": { - "MYSQL_USER": "my_username", - "MYSQL_PASSWORD": "@mySecretPassword" - } -} -``` - -### Set up environment variables in Apify Console - -In [Apify Console](https://console.apify.com/actors) select your Actor, you can set up variables into Source tab. -After setting up variables in the app, remove the `environmentVariables` from `.actor/actor.json`. Otherwise, variables from `.actor/actor.json` will override variables in the app. - -```json -{ - "actorSpecification": 1, - "name": "dataset-to-mysql", - "version": "0.1", - "buildTag": "latest" -} -``` - -#### How to set secret environment variables in .actor/actor.json - -CLI provides commands to manage secrets environment variables. Secrets are stored to the `~/.apify` directory. -You can add a new secret using the command: +To opt out, either run: ```bash -apify secrets:add mySecretPassword pwd1234 +apify telemetry disable ``` -After adding a new secret you can use the secret in `.actor/actor.json`. - -```text -{ - "actorSpecification": 1, - "name": "dataset-to-mysql", - ... - "environmentVariables": { - "MYSQL_PASSWORD": "@mySecretPassword" - }, - ... -} -``` +or set the `APIFY_CLI_DISABLE_TELEMETRY=1` environment variable. -### Need help? +## Contributing -To see all CLI commands simply run: +Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for local setup, code style, test categories, and PR guidelines. -```bash -apify help -``` - -To get information about a specific command run: - -```bash -apify help COMMAND -``` +## Feedback & support -Still haven't found what you were looking for? Please go to [Apify Help center](https://www.apify.com/help) -or [contact us](https://www.apify.com/contact). +- Report bugs or request features via [GitHub Issues](https://github.com/apify/apify-cli/issues) +- Browse the [Apify Help Center](https://www.apify.com/help) +- [Contact Apify support](https://www.apify.com/contact) +- Join the community on [Discord](https://discord.gg/crawlee-apify-801163717915574323) -## Command reference +## License -See a list of all our commands on the [reference page](https://docs.apify.com/cli/docs/reference) +[Apache-2.0](./LICENSE.md)