activitysmith-cli
Advanced tools
+2
-2
| { | ||
| "name": "activitysmith-cli", | ||
| "version": "1.6.0", | ||
| "version": "1.7.0", | ||
| "description": "Command-line interface for ActivitySmith. Send push notifications and manage Live Activities from your terminal.", | ||
@@ -43,5 +43,5 @@ "keywords": [ | ||
| "dependencies": { | ||
| "activitysmith": "^1.6.0", | ||
| "activitysmith": "^1.7.0", | ||
| "commander": "^12.1.0" | ||
| } | ||
| } |
+90
-13
@@ -8,3 +8,3 @@ # ActivitySmith CLI | ||
| - [Install](#install) | ||
| - [Install Skill (Codex/Claude/Other Skills-Compatible Agents)](#install-skill-codexclaudeother-skills-compatible-agents) | ||
| - [Agent Skill](#agent-skill) | ||
| - [Auth](#auth) | ||
@@ -33,8 +33,29 @@ - [Push Notifications](#push-notifications) | ||
| ## Install Skill (Codex/Claude/Other Skills-Compatible Agents) | ||
| ## Agent Skill | ||
| <p align="center"> | ||
| <img src="https://cdn.activitysmith.com/features/apple-shortcut-actions.png" alt="ActivitySmith Push Notification Actions with an Apple Shortcut action" width="680" /> | ||
| </p> | ||
| The ActivitySmith skill helps coding agents decide when and how to notify you. | ||
| Use it for prompts like: | ||
| - "Notify me when you're done." | ||
| - "Send me a push notification if you get blocked." | ||
| - "When the task finishes, the notification tap should run my Test Shortcut." | ||
| - "Show progress on my Lock Screen while you work." | ||
| The skill maps those requests to the CLI: | ||
| - Push Notifications for completion, blockers, and review requests | ||
| - `shortcuts://` redirection for a specific iPhone Shortcut | ||
| - action buttons for follow-up links or Shortcut buttons | ||
| - Live Activities for long-running progress | ||
| - widget metrics for values that should stay visible | ||
| Install the public skill from this repo: | ||
| ```bash | ||
| npx skills add ActivitySmithHQ/activitysmith-cli --skill activitysmith | ||
| npx -y skills@latest add ActivitySmithHQ/activitysmith-cli --skill activitysmith | ||
| ``` | ||
@@ -48,3 +69,3 @@ | ||
| The skill is agent-neutral and uses `ACTIVITYSMITH_API_KEY` auth plus the same CLI commands shown below. | ||
| The skill is agent-neutral and recipe-driven. It uses `ACTIVITYSMITH_API_KEY` auth plus the same CLI commands shown below. | ||
@@ -104,3 +125,3 @@ ## Auth | ||
| Actionable push notifications can open a URL on tap or trigger actions when someone long-presses the notification. | ||
| Push notification `--redirection` and `--actions` are optional. Use them to open HTTPS URLs, run a specific iPhone Shortcut with a `shortcuts://run-shortcut?name=...` URL, or trigger backend webhook workflows. | ||
| Webhooks are executed by the ActivitySmith backend. | ||
@@ -120,2 +141,7 @@ | ||
| { | ||
| "title": "Chat with Jarvis", | ||
| "type": "open_url", | ||
| "url": "shortcuts://run-shortcut?name=Jarvis" | ||
| }, | ||
| { | ||
| "title": "Create Incident", | ||
@@ -145,3 +171,3 @@ "type": "webhook", | ||
| There are five types of Live Activities: | ||
| There are six types of Live Activities: | ||
@@ -153,2 +179,3 @@ - `stats`: best for showing business numbers side by side, such as revenue, sales, new users, conversion, refunds, or any other value you want visible at a glance | ||
| - `alert`: best for status updates, such as feature adoption, reactivation, onboarding blockers, incidents, escalations, and other operational states | ||
| - `timer`: best for countdowns and elapsed runtime, like benchmark runs, uploads, backups, transcodes, and long-running jobs | ||
@@ -277,2 +304,27 @@ ### Start & Update Live Activity | ||
| #### Timer | ||
| <p align="center"> | ||
| <img | ||
| src="https://cdn.activitysmith.com/features/timer-live-activity.png" | ||
| alt="Timer Live Activity showing a benchmark run countdown" | ||
| width="680" | ||
| /> | ||
| </p> | ||
| ```bash | ||
| activitysmith activity stream benchmark-run \ | ||
| --content-state '{ | ||
| "title": "Benchmark Run", | ||
| "subtitle": "sampling", | ||
| "type": "timer", | ||
| "durationSeconds": 300, | ||
| "color": "cyan" | ||
| }' | ||
| ``` | ||
| For a countdown, send `duration_seconds`. You can update `title`, `subtitle`, `color`, or any other visible field as the work changes. Leave `duration_seconds` out unless you want to change the timer. | ||
| To start at 00:00 and count up, set `counts_down: false` and leave out `duration_seconds`. | ||
| ### End Live Activity | ||
@@ -298,5 +350,8 @@ | ||
| Live Activities can include one optional action button. Use it to open a URL from the Live Activity or trigger a backend webhook. | ||
| For Alert Live Activities, set `color` in `--content-state` to tint the action button. `icon.color` and `badge.color` only affect the icon and badge. | ||
| Live Activities can include one optional action button. | ||
| - `open_url`: open an HTTPS URL. | ||
| - `open_url` with a `shortcuts://` URL: run an Apple Shortcut, for example to open an app. | ||
| - `webhook`: trigger a backend GET/POST workflow. | ||
| <p align="center"> | ||
@@ -324,3 +379,3 @@ <img | ||
| --action '{ | ||
| "title": "Open Dashboard", | ||
| "title": "Dashboard", | ||
| "type": "open_url", | ||
@@ -331,2 +386,20 @@ "url": "https://ops.example.com/servers/prod-web-1" | ||
| #### Apple Shortcut action | ||
| ```bash | ||
| activitysmith activity stream deploy-payments-api \ | ||
| --content-state '{ | ||
| "title": "Deploying payments-api", | ||
| "subtitle": "Running database migrations", | ||
| "type": "segmented_progress", | ||
| "numberOfSteps": 5, | ||
| "currentStep": 3 | ||
| }' \ | ||
| --action '{ | ||
| "title": "Chat with Jarvis", | ||
| "type": "open_url", | ||
| "url": "shortcuts://run-shortcut?name=Jarvis" | ||
| }' | ||
| ``` | ||
| #### Webhook action | ||
@@ -484,2 +557,4 @@ | ||
| - `--upper-limit <number>` | ||
| - `--duration-seconds <number>` | ||
| - `--counts-down <true|false>` | ||
| - `--color <color>` | ||
@@ -489,2 +564,4 @@ - `--step-color <color>` | ||
| For `timer`, use `--duration-seconds` for a countdown. To start at 00:00 and count up, use `--counts-down false` and leave out `--duration-seconds`. | ||
| Live Activity action options: | ||
@@ -506,6 +583,6 @@ | ||
| - `activity stream`: `--title`, `--type`, plus `--metrics`, `--number-of-steps` and `--current-step`, `--percentage`, or `--value` with `--upper-limit` | ||
| - `activity start`: `--title`, `--type`, plus `--metrics`, `--number-of-steps` and `--current-step`, `--percentage`, or `--value` with `--upper-limit` | ||
| - `activity update`: `--title`, plus `--metrics`, `--current-step`, `--percentage`, or `--value` with `--upper-limit` | ||
| - `activity end`: `--title`, plus `--metrics`, `--current-step`, `--percentage`, or `--value` with `--upper-limit` | ||
| - `activity stream`: `--title`, `--type`, plus `--metrics`, `--number-of-steps` and `--current-step`, `--percentage`, `--value` with `--upper-limit`, or timer fields | ||
| - `activity start`: `--title`, `--type`, plus `--metrics`, `--number-of-steps` and `--current-step`, `--percentage`, `--value` with `--upper-limit`, or timer fields | ||
| - `activity update`: `--title`, plus `--metrics`, `--current-step`, `--percentage`, `--value` with `--upper-limit`, or timer fields | ||
| - `activity end`: `--title`, plus `--metrics`, `--current-step`, `--percentage`, `--value` with `--upper-limit`, or timer fields | ||
| - `activity end-stream`: no content state is required, but if you provide one it follows the same rules as `activity end` | ||
@@ -512,0 +589,0 @@ |
+71
-4
@@ -40,2 +40,18 @@ #!/usr/bin/env node | ||
| const parseBooleanOption = (label) => (value) => { | ||
| if (typeof value !== "string") { | ||
| throw new InvalidArgumentError(`${label} must be true or false`); | ||
| } | ||
| const normalized = value.trim().toLowerCase(); | ||
| if (normalized === "true") { | ||
| return true; | ||
| } | ||
| if (normalized === "false") { | ||
| return false; | ||
| } | ||
| throw new InvalidArgumentError(`${label} must be true or false`); | ||
| }; | ||
| const parseChannelsOption = (value) => { | ||
@@ -171,2 +187,12 @@ if (typeof value !== "string") { | ||
| ) | ||
| .option( | ||
| "--duration-seconds <number>", | ||
| "Timer duration in seconds", | ||
| parseNumberOption("duration-seconds") | ||
| ) | ||
| .option( | ||
| "--counts-down <boolean>", | ||
| "Set to false for an elapsed timer", | ||
| parseBooleanOption("counts-down") | ||
| ) | ||
| .option("--color <color>", "Content state color") | ||
@@ -306,6 +332,7 @@ .option("--step-color <color>", "Content state step color"); | ||
| normalizedType !== "stats" && | ||
| normalizedType !== "alert" | ||
| normalizedType !== "alert" && | ||
| normalizedType !== "timer" | ||
| ) { | ||
| throw new Error( | ||
| "contentState.type must be one of: segmented_progress, progress, metrics, stats, alert" | ||
| "contentState.type must be one of: segmented_progress, progress, metrics, stats, alert, timer" | ||
| ); | ||
@@ -324,2 +351,5 @@ } | ||
| const hasMetrics = hasOwn(contentState, "metrics"); | ||
| const hasDurationSeconds = hasOwn(contentState, "durationSeconds"); | ||
| const hasCountsDown = hasOwn(contentState, "countsDown"); | ||
| const hasTimerFields = hasDurationSeconds || hasCountsDown; | ||
@@ -351,2 +381,10 @@ if (hasValue !== hasUpperLimit) { | ||
| if (hasDurationSeconds && contentState.durationSeconds <= 0) { | ||
| throw new Error("contentState.durationSeconds must be greater than 0"); | ||
| } | ||
| if (hasCountsDown && typeof contentState.countsDown !== "boolean") { | ||
| throw new Error("contentState.countsDown must be true or false"); | ||
| } | ||
| const hasSegmentedFields = hasNumberOfSteps || hasCurrentStep || hasStepColor; | ||
@@ -482,2 +520,11 @@ const hasProgressFields = hasPercentage || hasValue || hasUpperLimit; | ||
| if (effectiveType === "timer") { | ||
| if (!hasDurationSeconds && contentState.countsDown !== false) { | ||
| throw new Error( | ||
| `timer ${mode} requires contentState.durationSeconds, or contentState.countsDown=false` | ||
| ); | ||
| } | ||
| return; | ||
| } | ||
| if (!hasPercentage && !hasValue) { | ||
@@ -523,5 +570,15 @@ throw new Error( | ||
| if (!hasSegmentedFields && !hasProgressFields && !hasMetrics && !hasAlertFields) { | ||
| if (effectiveType === "timer") { | ||
| return; | ||
| } | ||
| if ( | ||
| !hasSegmentedFields && | ||
| !hasProgressFields && | ||
| !hasMetrics && | ||
| !hasAlertFields && | ||
| !hasTimerFields | ||
| ) { | ||
| throw new Error( | ||
| `contentState for activity ${mode} must include metrics, segmented_progress fields, progress fields, or alert fields` | ||
| `contentState for activity ${mode} must include metrics, segmented_progress fields, progress fields, alert fields, or timer fields` | ||
| ); | ||
@@ -717,2 +774,10 @@ } | ||
| if (options.durationSeconds !== undefined) { | ||
| contentState.durationSeconds = options.durationSeconds; | ||
| } | ||
| if (options.countsDown !== undefined) { | ||
| contentState.countsDown = options.countsDown; | ||
| } | ||
| if (options.color !== undefined) { | ||
@@ -756,2 +821,4 @@ contentState.color = options.color; | ||
| autoDismissMinutes: "auto_dismiss_minutes", | ||
| durationSeconds: "duration_seconds", | ||
| countsDown: "counts_down", | ||
| }; | ||
@@ -758,0 +825,0 @@ |
56464
8.15%1151
5.31%583
15.22%Updated