New:Socket for Asana Is Now Available.Learn more
Get Started

activitysmith-cli

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

activitysmith-cli - npm Package Compare versions

Comparing version
1.1.0
to
1.3.0
+2
-2
package.json
{
"name": "activitysmith-cli",
"version": "1.1.0",
"version": "1.3.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.1.0",
"activitysmith": "^1.3.0",
"commander": "^12.1.0"
}
}
+184
-35

@@ -5,2 +5,25 @@ # ActivitySmith CLI

## Table of Contents
- [Install](#install)
- [Install Skill (Codex/Claude/Other Skills-Compatible Agents)](#install-skill-codexclaudeother-skills-compatible-agents)
- [Auth](#auth)
- [Push Notifications](#push-notifications)
- [Send Push Notification](#send-push-notification)
- [Rich Push Notifications with Media](#rich-push-notifications-with-media)
- [Actionable Push Notifications](#actionable-push-notifications)
- [Live Activities](#live-activities)
- [Simple: Let ActivitySmith manage the Live Activity for you](#simple-let-activitysmith-manage-the-live-activity-for-you)
- [Advanced: Full lifecycle control](#advanced-full-lifecycle-control)
- [Stats](#stats)
- [Metrics](#metrics)
- [Segmented Progress](#segmented-progress)
- [Progress](#progress)
- [Live Activity Action](#live-activity-action)
- [Channels](#channels)
- [Widgets](#widgets)
- [Aliases](#aliases)
- [Content State Options](#content-state-options)
- [Output](#output)
## Install

@@ -121,25 +144,28 @@

<p align="center">
<img src="https://cdn.activitysmith.com/features/metrics-live-activity-action.png" alt="Live Activities example" width="680" />
<img src="https://cdn.activitysmith.com/features/metrics-live-activity-action.png" alt="Metrics Live Activity screenshot" width="680" />
</p>
ActivitySmith supports two ways to drive Live Activities:
There are four types of Live Activities:
- Recommended: stream updates with `activitysmith activity stream ...`
- Advanced: manual lifecycle control with `activity start`, `activity update`, and `activity end`
- `stats`: best for compact business or product stats like revenue, orders, conversion, and average order value
- `metrics`: best for live operational stats like server CPU and memory, queue depth, or replica lag
- `segmented_progress`: best for step-based workflows like deployments, backups, and ETL pipelines
- `progress`: best for continuous jobs like uploads, reindexes, and long-running migrations tracked as a percentage
Use stream updates when you want the easiest, stateless flow. You do not need to
store `activity_id` or manage lifecycle state yourself. Send the latest state
for a stable `stream_key` and ActivitySmith will start or update the Live
Activity for you. When the tracked process is over, call `activity end-stream`.
When working with Live Activities via our API, you have two approaches tailored
to different needs. First, the stateless mode is the simplest path - one API
call can initiate or update an activity, and another ends it - no state
tracking on your side.
Use the manual lifecycle commands when you need direct control over a specific
Live Activity instance.
This is ideal if you want minimal complexity, perfect for automated workflows
like cron jobs.
Live Activity UI types:
In contrast, if you need precise lifecycle control, the classic approach offers
distinct calls for start, updates, and end, giving you full control over the
activity's state.
- `metrics`: best for live operational stats like server CPU and memory, queue depth, or replica lag
- `segmented_progress`: best for step-based workflows like deployments, backups, and ETL pipelines
- `progress`: best for continuous jobs like uploads, reindexes, and long-running migrations tracked as a percentage
In the following sections, we'll break down how to implement each method so you
can choose what fits your use case best.
### Recommended: Stream updates
### Simple: Let ActivitySmith manage the Live Activity for you

@@ -151,2 +177,25 @@ Use a stable `stream_key` to identify the system or workflow you are tracking,

#### Stats
<p align="center">
<img src="https://cdn.activitysmith.com/features/stats-live-activity.png" alt="Stats stream example" width="680" />
</p>
```bash
activitysmith activity stream sales-hourly \
--content-state '{
"title": "Sales",
"subtitle": "last hour",
"type": "stats",
"metrics": [
{ "label": "Revenue", "value": "$2430", "color": "blue" },
{ "label": "Orders", "value": "37", "color": "green" },
{ "label": "Conversion", "value": "4.8%", "color": "magenta" },
{ "label": "Avg Order", "value": "$65.68", "color": "yellow" },
{ "label": "Refunds", "value": "$84", "color": "red" },
{ "label": "New Buyers", "value": "18", "color": "cyan" }
]
}'
```
#### Metrics

@@ -238,8 +287,6 @@

### Advanced: Manual lifecycle control
### Advanced: Full lifecycle control
Use these commands when you want to manage the Live Activity lifecycle yourself.
Use these commands when you want to manage the Live Activity lifecycle yourself:
#### Shared flow
1. Run `activitysmith activity start ...`.

@@ -253,2 +300,74 @@ 2. Save the returned `activity_id`.

### Stats
Keep your key numbers on your Lock Screen. `stats` fits up to 8 labeled values,
such as revenue, orders, conversion, uptime, or any other business metric you
want visible at a glance. Each metric can use a formatted string or number as
its `value`. Add `color` to a metric to show an accent dot next to its label;
omit `color` to show the label without a dot.
#### Start
<p align="center">
<img src="https://cdn.activitysmith.com/features/stats-live-activity.png" alt="Stats Live Activity with sales revenue, orders, conversion, and average order value" width="680" />
</p>
```bash
activitysmith activity start \
--content-state '{
"title": "Sales",
"subtitle": "last hour",
"type": "stats",
"metrics": [
{ "label": "Revenue", "value": "$2430", "color": "blue" },
{ "label": "Orders", "value": "37", "color": "green" },
{ "label": "Conversion", "value": "4.8%", "color": "magenta" },
{ "label": "Avg Order", "value": "$65.68", "color": "yellow" },
{ "label": "Refunds", "value": "$84", "color": "red" },
{ "label": "New Buyers", "value": "18", "color": "cyan" }
]
}'
```
#### Update
```bash
activitysmith activity update \
--activity-id "<activityId>" \
--content-state '{
"title": "Sales",
"subtitle": "last hour",
"type": "stats",
"metrics": [
{ "label": "Revenue", "value": "$3180", "color": "blue" },
{ "label": "Orders", "value": "51", "color": "green" },
{ "label": "Conversion", "value": "5.2%", "color": "magenta" },
{ "label": "Avg Order", "value": "$62.35", "color": "yellow" },
{ "label": "Refunds", "value": "$126", "color": "red" },
{ "label": "New Buyers", "value": "24", "color": "cyan" }
]
}'
```
#### End
```bash
activitysmith activity end \
--activity-id "<activityId>" \
--content-state '{
"title": "Sales",
"subtitle": "last hour",
"type": "stats",
"metrics": [
{ "label": "Revenue", "value": "$3460", "color": "blue" },
{ "label": "Orders", "value": "58", "color": "green" },
{ "label": "Conversion", "value": "5.4%", "color": "magenta" },
{ "label": "Avg Order", "value": "$59.66", "color": "yellow" },
{ "label": "Refunds", "value": "$92", "color": "red" },
{ "label": "New Buyers", "value": "31", "color": "cyan" }
],
"autoDismissMinutes": 2
}'
```
### Metrics Type

@@ -321,6 +440,6 @@

Use `segmented_progress` when progress is easier to follow as steps instead of a
raw percentage. It fits jobs like deployments, backups, ETL pipelines, and
checklists where "step 2 of 3" is more useful than "67%". `numberOfSteps` is
dynamic, so you can increase or decrease it later if the workflow changes.
Use `segmented_progress` for jobs and workflows that move through clear steps or
phases. It fits jobs like deployments, backups, ETL pipelines, and checklists.
`numberOfSteps` is dynamic, so you can increase or decrease it later if the
workflow changes.

@@ -437,3 +556,3 @@ #### Start

Just like Actionable Push Notifications, Live Activities can have a button that opens a URL in a browser or triggers a webhook. Webhooks are executed by the ActivitySmith backend.
Just like Actionable Push Notifications, Live Activities can have a button that opens provided URL in a browser or triggers a webhook. Webhooks are executed by the ActivitySmith backend.

@@ -466,2 +585,6 @@ <p align="center">

<p align="center">
<img src="https://cdn.activitysmith.com/features/live-activity-with-action.png?v=20260319-1" alt="Live Activity with action" width="680" />
</p>
```bash

@@ -471,17 +594,14 @@ activitysmith activity update \

--content-state '{
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{ "label": "CPU", "value": 91, "unit": "%" },
{ "label": "MEM", "value": 57, "unit": "%" }
]
"title": "Reindexing product search",
"subtitle": "Shard 7 of 12",
"numberOfSteps": 12,
"currentStep": 7
}' \
--action '{
"title": "Restart Service",
"title": "Pause Reindex",
"type": "webhook",
"url": "https://ops.example.com/hooks/servers/prod-web-1/restart",
"url": "https://ops.example.com/hooks/search/reindex/pause",
"method": "POST",
"body": {
"server_id": "prod-web-1",
"job_id": "reindex-2026-03-19",
"requested_by": "activitysmith-cli"

@@ -503,2 +623,26 @@ }

## Widgets
<p align="center">
<img src="https://cdn.activitysmith.com/features/lock-screen-widgets.png" alt="Lock screen widgets" width="680" />
</p>
ActivitySmith lets you display any value on your Lock Screen with widgets - SaaS metrics, revenue, signups, uptime, habits, or anything else you want to track. Create a metric in the <a href="https://activitysmith.com/app/widgets" target="_blank" rel="noopener noreferrer">web app</a>, then update the metric value using our API, add a widget to your lock screen and it will fetch the latest update automatically.
<p align="center">
<img src="https://cdn.activitysmith.com/features/create-widget-metric.png" alt="Create widget metric" width="680" />
</p>
Use the metric key to update its value.
```bash
activitysmith metrics update deploy.success_rate 99.9
```
String metric values work too.
```bash
activitysmith metrics update prod.status healthy
```
## Aliases

@@ -518,3 +662,3 @@

For `metrics`, you can also pass the metrics array directly:
For `metrics` and `stats`, you can also pass the metrics array directly:

@@ -547,2 +691,7 @@ - `--metrics <json-array>`

Widget metric options:
- `activitysmith metrics update <metric-key> <value>`
- `activitysmith metric update <metric-key> <value>` (alias)
Required fields:

@@ -549,0 +698,0 @@

@@ -57,2 +57,26 @@ #!/usr/bin/env node

const parseMetricValueArgument = (value) => {
if (typeof value !== "string") {
throw new InvalidArgumentError("value must be a string or number");
}
const trimmed = value.trim();
if (trimmed.length === 0) {
throw new InvalidArgumentError("value cannot be empty");
}
try {
const parsed = JSON.parse(trimmed);
if (typeof parsed === "string" || typeof parsed === "number") {
return parsed;
}
throw new InvalidArgumentError("value must be a string or number");
} catch (error) {
if (error instanceof InvalidArgumentError) {
throw error;
}
return value;
}
};
const normalizeHttpsUrl = (value, label) => {

@@ -216,2 +240,14 @@ if (typeof value !== "string" || value.trim().length === 0) {

const liveActivityMetricColors = new Set([
"blue",
"cyan",
"green",
"lime",
"magenta",
"orange",
"purple",
"red",
"yellow",
]);
const validateContentState = (contentState, mode) => {

@@ -229,6 +265,7 @@ const normalizedType =

normalizedType !== "progress" &&
normalizedType !== "metrics"
normalizedType !== "metrics" &&
normalizedType !== "stats"
) {
throw new Error(
"contentState.type must be one of: segmented_progress, progress, metrics"
"contentState.type must be one of: segmented_progress, progress, metrics, stats"
);

@@ -290,2 +327,6 @@ }

if (normalizedType === "stats" && contentState.metrics.length > 8) {
throw new Error("stats contentState.metrics supports up to 8 items");
}
contentState.metrics.forEach((metric, index) => {

@@ -296,4 +337,12 @@ assertPlainObject(metric, `contentState.metrics[${index}]`);

}
if (!Number.isFinite(metric.value)) {
throw new Error(`contentState.metrics[${index}].value must be a number`);
if (normalizedType === "stats") {
if (!Number.isFinite(metric.value) && !isNonEmptyString(metric.value)) {
throw new Error(
`contentState.metrics[${index}].value must be a number or non-empty string`
);
}
} else if (!Number.isFinite(metric.value)) {
throw new Error(
`contentState.metrics[${index}].value must be a number. Use contentState.type=stats for string values`
);
}

@@ -303,2 +352,14 @@ if (metric.unit !== undefined && typeof metric.unit !== "string") {

}
if (metric.color !== undefined) {
if (!isNonEmptyString(metric.color)) {
throw new Error(`contentState.metrics[${index}].color must be a string`);
}
if (!liveActivityMetricColors.has(metric.color.trim())) {
throw new Error(
`contentState.metrics[${index}].color must be one of: ${[
...liveActivityMetricColors,
].join(", ")}`
);
}
}
});

@@ -323,5 +384,5 @@ }

if (effectiveType === "metrics") {
if (effectiveType === "metrics" || effectiveType === "stats") {
if (!hasMetrics) {
throw new Error(`metrics ${mode} requires contentState.metrics`);
throw new Error(`${effectiveType} ${mode} requires contentState.metrics`);
}

@@ -357,5 +418,5 @@ return;

if (effectiveType === "metrics") {
if (effectiveType === "metrics" || effectiveType === "stats") {
if (!hasMetrics) {
throw new Error(`metrics ${mode} requires contentState.metrics`);
throw new Error(`${effectiveType} ${mode} requires contentState.metrics`);
}

@@ -914,2 +975,27 @@ return;

const metricsCommand = program
.command("metrics")
.alias("metric")
.description("Update widget metric values");
metricsCommand
.command("update")
.description("Update a widget metric value")
.argument("<metric-key>", "Metric key")
.argument("<value>", "Metric value")
.action(async (metricKey, rawValue) => {
const globalOptions = program.opts();
try {
const apiKey = requireApiKey(globalOptions);
const client = createClient(apiKey);
const value = parseMetricValueArgument(rawValue);
const response = await client.metrics.update(metricKey, value);
outputResult(response, globalOptions, ["Metric value updated."]);
} catch (error) {
await handleError(error, globalOptions);
}
});
const activityCommand = program

@@ -916,0 +1002,0 @@ .command("activity")