From 5679f70867dd02319289ba1408a90258303cf3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=28Honza=29=20Jir=C3=A1=C5=88?= Date: Mon, 3 Aug 2026 08:45:45 +0200 Subject: [PATCH 1/5] feat: add task publish and unpublish commands --- docs/reference.md | 43 ++++++++++++++++++++-- scripts/generate-cli-docs.ts | 2 + src/commands/task/_index.ts | 6 ++- src/commands/task/publish.ts | 67 ++++++++++++++++++++++++++++++++++ src/commands/task/unpublish.ts | 66 +++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 src/commands/task/publish.ts create mode 100644 src/commands/task/unpublish.ts diff --git a/docs/reference.md b/docs/reference.md index 09af9be11..d79952ba5 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1613,12 +1613,15 @@ These commands help you manage scheduled and configured Actor runs. Use them to ```sh DESCRIPTION - Run saved Apify tasks (named Actor configurations). Only 'task run' is - available; create and manage tasks in Apify Console. + Run and publish saved Apify tasks (named Actor configurations). Create and + manage tasks in Apify Console. SUBCOMMANDS - task run Executes predefined Actor task remotely using local - key-value store for input. + task run Executes predefined Actor task remotely using + local key-value store for input. + task publish Publishes the task on its public landing page. + task unpublish Unpublishes the task from its public landing + page. ``` ##### `apify task run` @@ -1645,6 +1648,38 @@ FLAGS -t, --timeout= Timeout for the Task run in seconds. Zero value means there is no timeout. ``` + +##### `apify task publish` + +```sh +DESCRIPTION + Publishes the task on its public landing page. + The task must belong to a public Actor and have its public display + configuration set up (in Apify Console, on the task Publication tab). + +USAGE + $ apify task publish + +ARGUMENTS + taskId Name or ID of the Task to publish (e.g. "my-task" or + "E2jjCZBezvAZnX8Rb"). +``` + +##### `apify task unpublish` + +```sh +DESCRIPTION + Unpublishes the task from its public landing page. + The public display configuration is preserved, so the task can be published + again later. + +USAGE + $ apify task unpublish + +ARGUMENTS + taskId Name or ID of the Task to unpublish (e.g. "my-task" or + "E2jjCZBezvAZnX8Rb"). +``` diff --git a/scripts/generate-cli-docs.ts b/scripts/generate-cli-docs.ts index a45eb8555..c14d5433d 100644 --- a/scripts/generate-cli-docs.ts +++ b/scripts/generate-cli-docs.ts @@ -114,6 +114,8 @@ const categories: Record = { // { command: Commands.task }, { command: Commands.taskRun }, + { command: Commands.taskPublish }, + { command: Commands.taskUnpublish }, ], 'mcp': [ // diff --git a/src/commands/task/_index.ts b/src/commands/task/_index.ts index f44286d6e..07edcaaf8 100644 --- a/src/commands/task/_index.ts +++ b/src/commands/task/_index.ts @@ -1,16 +1,18 @@ import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; +import { TaskPublishCommand } from './publish.js'; import { TaskRunCommand } from './run.js'; +import { TaskUnpublishCommand } from './unpublish.js'; export class TasksIndexCommand extends ApifyCommand { static override name = 'task' as const; - static override description = `Run saved Apify tasks (named Actor configurations). Only 'task run' is available; create and manage tasks in Apify Console.`; + static override description = `Run and publish saved Apify tasks (named Actor configurations). Create and manage tasks in Apify Console.`; static override group = 'Apify Console'; static override docsUrl = 'https://docs.apify.com/cli/docs/reference#apify-task'; - static override subcommands = [TaskRunCommand]; + static override subcommands = [TaskRunCommand, TaskPublishCommand, TaskUnpublishCommand]; async run() { this.printHelp(); diff --git a/src/commands/task/publish.ts b/src/commands/task/publish.ts new file mode 100644 index 000000000..6e4c4e2cb --- /dev/null +++ b/src/commands/task/publish.ts @@ -0,0 +1,67 @@ +import type { ApifyApiError } from 'apify-client'; +import chalk from 'chalk'; + +import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; +import { Args } from '../../lib/command-framework/args.js'; +import { error, success } from '../../lib/outputs.js'; +import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js'; + +export class TaskPublishCommand extends ApifyCommand { + static override name = 'publish' as const; + + static override description = + 'Publishes the task on its public landing page.\n' + + 'The task must belong to a public Actor and have its public display configuration set up ' + + '(in Apify Console, on the task Publication tab).'; + + static override examples = [ + { + description: 'Publish a task by name.', + command: 'apify task publish my-task', + }, + { + description: 'Publish a task by full ID.', + command: 'apify task publish E2jjCZBezvAZnX8Rb', + }, + ]; + + static override docsUrl = 'https://docs.apify.com/cli/docs/reference#apify-task-publish'; + + static override args = { + taskId: Args.string({ + required: true, + description: 'Name or ID of the Task to publish (e.g. "my-task" or "E2jjCZBezvAZnX8Rb").', + }), + }; + + async run() { + const apifyClient = await getLoggedClientOrThrow(); + const userInfo = await getLocalUserInfo(); + const usernameOrId = userInfo.username || (userInfo.id as string); + + const { taskId } = this.args; + const idOrName = taskId.includes('/') ? taskId : `${usernameOrId}/${taskId.toLowerCase()}`; + const taskClient = apifyClient.task(idOrName); + + const task = await taskClient.get(); + if (!task) { + error({ message: `Cannot find Task with ID or name '${taskId}' in your account.` }); + return; + } + + try { + await taskClient.publish(); + + success({ + message: `Task ${chalk.yellow(task.name)} has been published.`, + stdout: true, + }); + } catch (err) { + const casted = err as ApifyApiError; + + error({ + message: `Failed to publish Task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, + }); + } + } +} diff --git a/src/commands/task/unpublish.ts b/src/commands/task/unpublish.ts new file mode 100644 index 000000000..f4b7f22b3 --- /dev/null +++ b/src/commands/task/unpublish.ts @@ -0,0 +1,66 @@ +import type { ApifyApiError } from 'apify-client'; +import chalk from 'chalk'; + +import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; +import { Args } from '../../lib/command-framework/args.js'; +import { error, success } from '../../lib/outputs.js'; +import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js'; + +export class TaskUnpublishCommand extends ApifyCommand { + static override name = 'unpublish' as const; + + static override description = + 'Unpublishes the task from its public landing page.\n' + + 'The public display configuration is preserved, so the task can be published again later.'; + + static override examples = [ + { + description: 'Unpublish a task by name.', + command: 'apify task unpublish my-task', + }, + { + description: 'Unpublish a task by full ID.', + command: 'apify task unpublish E2jjCZBezvAZnX8Rb', + }, + ]; + + static override docsUrl = 'https://docs.apify.com/cli/docs/reference#apify-task-unpublish'; + + static override args = { + taskId: Args.string({ + required: true, + description: 'Name or ID of the Task to unpublish (e.g. "my-task" or "E2jjCZBezvAZnX8Rb").', + }), + }; + + async run() { + const apifyClient = await getLoggedClientOrThrow(); + const userInfo = await getLocalUserInfo(); + const usernameOrId = userInfo.username || (userInfo.id as string); + + const { taskId } = this.args; + const idOrName = taskId.includes('/') ? taskId : `${usernameOrId}/${taskId.toLowerCase()}`; + const taskClient = apifyClient.task(idOrName); + + const task = await taskClient.get(); + if (!task) { + error({ message: `Cannot find Task with ID or name '${taskId}' in your account.` }); + return; + } + + try { + await taskClient.unpublish(); + + success({ + message: `Task ${chalk.yellow(task.name)} has been unpublished.`, + stdout: true, + }); + } catch (err) { + const casted = err as ApifyApiError; + + error({ + message: `Failed to unpublish Task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, + }); + } + } +} From cbd7a5a4f8ca028059a7fdf29c28a79685052c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=28Honza=29=20Jir=C3=A1=C5=88?= Date: Thu, 6 Aug 2026 15:42:18 +0200 Subject: [PATCH 2/5] feat: review feedback changes [internal] --- docs/reference.md | 13 +++++++------ src/commands/task/publish.ts | 14 +++++++++----- src/commands/task/unpublish.ts | 14 +++++++++----- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index d79952ba5..d714460e6 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1655,14 +1655,15 @@ FLAGS DESCRIPTION Publishes the task on its public landing page. The task must belong to a public Actor and have its public display - configuration set up (in Apify Console, on the task Publication tab). + configuration set up (in Apify Console, on the task Publication tab). Requires + write access to the task and to its Actor. USAGE $ apify task publish ARGUMENTS - taskId Name or ID of the Task to publish (e.g. "my-task" or - "E2jjCZBezvAZnX8Rb"). + taskId Name of the Task to publish, or its full name (e.g. "my-task" or + "username/my-task"). ``` ##### `apify task unpublish` @@ -1671,14 +1672,14 @@ ARGUMENTS DESCRIPTION Unpublishes the task from its public landing page. The public display configuration is preserved, so the task can be published - again later. + again later. Requires write access to the task and to its Actor. USAGE $ apify task unpublish ARGUMENTS - taskId Name or ID of the Task to unpublish (e.g. "my-task" or - "E2jjCZBezvAZnX8Rb"). + taskId Name of the Task to unpublish, or its full name (e.g. "my-task" + or "username/my-task"). ``` diff --git a/src/commands/task/publish.ts b/src/commands/task/publish.ts index 6e4c4e2cb..c85ee7b16 100644 --- a/src/commands/task/publish.ts +++ b/src/commands/task/publish.ts @@ -3,6 +3,7 @@ import chalk from 'chalk'; import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; import { Args } from '../../lib/command-framework/args.js'; +import { CommandExitCodes } from '../../lib/consts.js'; import { error, success } from '../../lib/outputs.js'; import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js'; @@ -12,7 +13,8 @@ export class TaskPublishCommand extends ApifyCommand static override description = 'Publishes the task on its public landing page.\n' + 'The task must belong to a public Actor and have its public display configuration set up ' + - '(in Apify Console, on the task Publication tab).'; + '(in Apify Console, on the task Publication tab). ' + + 'Requires write access to the task and to its Actor.'; static override examples = [ { @@ -20,8 +22,8 @@ export class TaskPublishCommand extends ApifyCommand command: 'apify task publish my-task', }, { - description: 'Publish a task by full ID.', - command: 'apify task publish E2jjCZBezvAZnX8Rb', + description: 'Publish a task by its full name.', + command: 'apify task publish username/my-task', }, ]; @@ -30,7 +32,7 @@ export class TaskPublishCommand extends ApifyCommand static override args = { taskId: Args.string({ required: true, - description: 'Name or ID of the Task to publish (e.g. "my-task" or "E2jjCZBezvAZnX8Rb").', + description: 'Name of the Task to publish, or its full name (e.g. "my-task" or "username/my-task").', }), }; @@ -45,7 +47,8 @@ export class TaskPublishCommand extends ApifyCommand const task = await taskClient.get(); if (!task) { - error({ message: `Cannot find Task with ID or name '${taskId}' in your account.` }); + error({ message: `Cannot find Task with name '${taskId}' in your account.` }); + process.exitCode = CommandExitCodes.NotFound; return; } @@ -62,6 +65,7 @@ export class TaskPublishCommand extends ApifyCommand error({ message: `Failed to publish Task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, }); + process.exitCode = CommandExitCodes.RunFailed; } } } diff --git a/src/commands/task/unpublish.ts b/src/commands/task/unpublish.ts index f4b7f22b3..bdb288237 100644 --- a/src/commands/task/unpublish.ts +++ b/src/commands/task/unpublish.ts @@ -3,6 +3,7 @@ import chalk from 'chalk'; import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; import { Args } from '../../lib/command-framework/args.js'; +import { CommandExitCodes } from '../../lib/consts.js'; import { error, success } from '../../lib/outputs.js'; import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js'; @@ -11,7 +12,8 @@ export class TaskUnpublishCommand extends ApifyCommand Date: Mon, 10 Aug 2026 14:58:34 +0200 Subject: [PATCH 3/5] chore: update imports - review feedback [internal] --- src/commands/task/publish.ts | 2 ++ src/commands/task/unpublish.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/commands/task/publish.ts b/src/commands/task/publish.ts index c85ee7b16..3d4e3ad2f 100644 --- a/src/commands/task/publish.ts +++ b/src/commands/task/publish.ts @@ -1,3 +1,5 @@ +import process from 'node:process'; + import type { ApifyApiError } from 'apify-client'; import chalk from 'chalk'; diff --git a/src/commands/task/unpublish.ts b/src/commands/task/unpublish.ts index bdb288237..2b9645f9f 100644 --- a/src/commands/task/unpublish.ts +++ b/src/commands/task/unpublish.ts @@ -1,3 +1,5 @@ +import process from 'node:process'; + import type { ApifyApiError } from 'apify-client'; import chalk from 'chalk'; From 4984aa7a743b213ac82900e81caf4247021f0a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=28Honza=29=20Jir=C3=A1=C5=88?= Date: Tue, 11 Aug 2026 10:05:30 +0200 Subject: [PATCH 4/5] chore: update copy --- docs/reference.md | 12 ++++++------ src/commands/task/publish.ts | 8 ++++---- src/commands/task/unpublish.ts | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index e4a4fe0cd..c1b1abe73 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1693,15 +1693,15 @@ FLAGS DESCRIPTION Publishes the task on its public landing page. The task must belong to a public Actor and have its public display - configuration set up (in Apify Console, on the task Publication tab). Requires - write access to the task and to its Actor. + configuration set up on the task Publication tab in Apify Console. Requires + write access to the task and to its Actor. USAGE $ apify task publish ARGUMENTS - taskId Name of the Task to publish, or its full name (e.g. "my-task" or - "username/my-task"). + taskId Name of the task to publish. For example, "my-task" or + "username/my-task". ``` ##### `apify task unpublish` @@ -1716,8 +1716,8 @@ USAGE $ apify task unpublish ARGUMENTS - taskId Name of the Task to unpublish, or its full name (e.g. "my-task" - or "username/my-task"). + taskId Name of the task to unpublish. For example, "my-task" or + "username/my-task". ``` diff --git a/src/commands/task/publish.ts b/src/commands/task/publish.ts index 3d4e3ad2f..bd43ea488 100644 --- a/src/commands/task/publish.ts +++ b/src/commands/task/publish.ts @@ -15,7 +15,7 @@ export class TaskPublishCommand extends ApifyCommand static override description = 'Publishes the task on its public landing page.\n' + 'The task must belong to a public Actor and have its public display configuration set up ' + - '(in Apify Console, on the task Publication tab). ' + + 'on the task Publication tab in Apify Console. ' + 'Requires write access to the task and to its Actor.'; static override examples = [ @@ -24,7 +24,7 @@ export class TaskPublishCommand extends ApifyCommand command: 'apify task publish my-task', }, { - description: 'Publish a task by its full name.', + description: 'Publish a task by full name.', command: 'apify task publish username/my-task', }, ]; @@ -34,7 +34,7 @@ export class TaskPublishCommand extends ApifyCommand static override args = { taskId: Args.string({ required: true, - description: 'Name of the Task to publish, or its full name (e.g. "my-task" or "username/my-task").', + description: 'Name of the task to publish. For example, "my-task" or "username/my-task".', }), }; @@ -65,7 +65,7 @@ export class TaskPublishCommand extends ApifyCommand const casted = err as ApifyApiError; error({ - message: `Failed to publish Task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, + message: `Failed to publish task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, }); process.exitCode = CommandExitCodes.RunFailed; } diff --git a/src/commands/task/unpublish.ts b/src/commands/task/unpublish.ts index 2b9645f9f..26c2a310e 100644 --- a/src/commands/task/unpublish.ts +++ b/src/commands/task/unpublish.ts @@ -23,7 +23,7 @@ export class TaskUnpublishCommand extends ApifyCommand Date: Tue, 11 Aug 2026 14:40:46 +0200 Subject: [PATCH 5/5] chore: bump apify-client --- package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 719230ccc..ef999ffed 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "@skyra/jaro-winkler": "^1.1.1", "adm-zip": "~0.6.0", "ajv": "~8.20.0", - "apify-client": "^2.23.3", + "apify-client": "^2.25.0", "archiver": "~8.0.0", "axios": "^1.15.0", "chalk": "~6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d37777901..928902905 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,8 +268,8 @@ importers: specifier: ~8.20.0 version: 8.20.0 apify-client: - specifier: ^2.23.3 - version: 2.24.0 + specifier: ^2.25.0 + version: 2.25.0 archiver: specifier: ~8.0.0 version: 8.0.0 @@ -4562,8 +4562,8 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - apify-client@2.24.0: - resolution: {integrity: sha512-z82DywSpMc6djz+HwEO9YFPAdxChOCKVWpzF0p8rH7hp5rXk5KuPqpmtwC9c3LiiRwTPRC/6y0JxbMqD2ndvwQ==} + apify-client@2.25.0: + resolution: {integrity: sha512-g6ttHJ4Au/Gg0iDHIevN3CvTbJfey9DUXUXJxe0ORF6JIYaVVfKdyJjINGb6/49gOpt/62ZFPw+HSEVIzrwR5w==} apify@3.7.2: resolution: {integrity: sha512-I4R5Qd1X11vk5/1U0CxKSsMhNwER/3MntePEQb9Pbtf942OhQLh5IURrJZufqtpimkqRy44SlQMU6UhPdoFXhA==} @@ -14527,7 +14527,7 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 - apify-client@2.24.0: + apify-client@2.25.0: dependencies: '@apify/consts': 2.56.1 '@apify/log': 2.5.47 @@ -14555,7 +14555,7 @@ snapshots: '@crawlee/core': 3.17.0 '@crawlee/types': 3.17.0 '@crawlee/utils': 3.17.0 - apify-client: 2.24.0 + apify-client: 2.25.0 fs-extra: 11.4.0 ow: 0.28.2 semver: 7.8.5