clawtick 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +172 -0
- package/dist/api-client.d.ts +34 -0
- package/dist/api-client.js +90 -0
- package/dist/api-client.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +299 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/validation.d.ts +62 -0
- package/dist/validation.js +174 -0
- package/dist/validation.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abdelhak Akermi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# ClawTick CLI 🦞
|
|
2
|
+
|
|
3
|
+
> Cloud-powered cron scheduling for [OpenClaw](https://github.com/nicepkg/openclaw). Reliable triggers, real-time monitoring, zero missed jobs.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/clawtick)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Why ClawTick?
|
|
9
|
+
|
|
10
|
+
OpenClaw's built-in scheduler has known reliability issues — jobs silently fail, timers wedge, and `schedule.kind: 'every'` never fires. ClawTick replaces all of that with cloud infrastructure that works.
|
|
11
|
+
|
|
12
|
+
- Rock-solid cron scheduling
|
|
13
|
+
- Dashboard + CLI to manage everything
|
|
14
|
+
- Multi-channel delivery (WhatsApp, Telegram, Slack, Discord)
|
|
15
|
+
- Execution history and failure tracking
|
|
16
|
+
- Works with your existing OpenClaw gateway
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g clawtick
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### 1. Get an API key
|
|
27
|
+
|
|
28
|
+
Sign up at [clawtick.com](https://clawtick.com) and generate a key from **Dashboard → API Keys**.
|
|
29
|
+
|
|
30
|
+
### 2. Login
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
clawtick login --key cp_your_api_key
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 3. Configure your gateway
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
clawtick gateway set --url http://your-vps:80 --token your_gateway_token
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 4. Create your first job
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
clawtick job create \
|
|
46
|
+
--cron "0 9 * * *" \
|
|
47
|
+
--message "Good morning! Check my emails" \
|
|
48
|
+
--name "Morning check"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
That's it. The job will fire daily at 9 AM UTC.
|
|
52
|
+
|
|
53
|
+
## Commands
|
|
54
|
+
|
|
55
|
+
### Authentication
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
clawtick login --key <api-key> # Authenticate
|
|
59
|
+
clawtick logout # Remove credentials
|
|
60
|
+
clawtick whoami # Check connection status
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Jobs
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
clawtick job list # List all jobs
|
|
67
|
+
clawtick job create [options] # Create a new job
|
|
68
|
+
clawtick job update <id> [options] # Update a job
|
|
69
|
+
clawtick job remove <id> # Delete a job
|
|
70
|
+
clawtick job trigger <id> # Run a job now
|
|
71
|
+
clawtick job enable <id> # Resume a paused job
|
|
72
|
+
clawtick job disable <id> # Pause a job
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Gateway
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
clawtick gateway set --url <url> --token <token>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Account
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
clawtick status # View plan, usage, stats
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Job Options
|
|
88
|
+
|
|
89
|
+
| Option | Required | Default | Description |
|
|
90
|
+
|--------|----------|---------|-------------|
|
|
91
|
+
| `--cron` | Yes | — | Cron expression (5-field) |
|
|
92
|
+
| `--message` | Yes | — | Message sent to the agent |
|
|
93
|
+
| `--name` | No | Auto | Job display name |
|
|
94
|
+
| `--agent` | No | `main` | Target agent ID |
|
|
95
|
+
| `--channel` | No | — | Delivery channel |
|
|
96
|
+
| `--deliver` | No | `false` | Send agent response to channel |
|
|
97
|
+
| `--reply-to` | No | — | Channel-specific target |
|
|
98
|
+
| `--timezone` | No | `UTC` | IANA timezone |
|
|
99
|
+
|
|
100
|
+
### Channels
|
|
101
|
+
|
|
102
|
+
| Channel | `--reply-to` value |
|
|
103
|
+
|---------|-------------------|
|
|
104
|
+
| `whatsapp` | Phone number (default chat) |
|
|
105
|
+
| `telegram` | Chat ID |
|
|
106
|
+
| `slack` | Channel name (`#general`) |
|
|
107
|
+
| `discord` | Channel ID |
|
|
108
|
+
|
|
109
|
+
## Examples
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Daily morning briefing to WhatsApp
|
|
113
|
+
clawtick job create \
|
|
114
|
+
--cron "0 9 * * *" \
|
|
115
|
+
--message "Summarize my calendar and top emails" \
|
|
116
|
+
--name "morning-briefing" \
|
|
117
|
+
--agent main \
|
|
118
|
+
--channel whatsapp \
|
|
119
|
+
--deliver
|
|
120
|
+
|
|
121
|
+
# Hourly status check to Telegram
|
|
122
|
+
clawtick job create \
|
|
123
|
+
--cron "0 * * * *" \
|
|
124
|
+
--message "System status check" \
|
|
125
|
+
--name "status-check" \
|
|
126
|
+
--channel telegram \
|
|
127
|
+
--deliver \
|
|
128
|
+
--reply-to 123456789
|
|
129
|
+
|
|
130
|
+
# Weekly report every Monday
|
|
131
|
+
clawtick job create \
|
|
132
|
+
--cron "0 10 * * 1" \
|
|
133
|
+
--message "Generate weekly activity report" \
|
|
134
|
+
--name "weekly-report" \
|
|
135
|
+
--channel slack \
|
|
136
|
+
--deliver \
|
|
137
|
+
--reply-to "#reports"
|
|
138
|
+
|
|
139
|
+
# Health check every 5 minutes (logs only, no delivery)
|
|
140
|
+
clawtick job create \
|
|
141
|
+
--cron "*/5 * * * *" \
|
|
142
|
+
--message "Health check ping" \
|
|
143
|
+
--name "health-check"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Plans
|
|
147
|
+
|
|
148
|
+
| | Free | Starter ($9/mo) | Pro ($29/mo) |
|
|
149
|
+
|---|---|---|---|
|
|
150
|
+
| Jobs | 10 | 50 | Unlimited |
|
|
151
|
+
| Triggers/month | 500 | 5,000 | 50,000 |
|
|
152
|
+
| History | 14 days | 30 days | 90 days |
|
|
153
|
+
|
|
154
|
+
Sign up at [clawtick.com](https://clawtick.com) — free plan, no credit card.
|
|
155
|
+
|
|
156
|
+
## Configuration
|
|
157
|
+
|
|
158
|
+
Config is stored in `~/.clawtick/config.json`. You can also use environment variables:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
export CLAWPULSE_API_KEY=cp_your_key # Skip login
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Links
|
|
165
|
+
|
|
166
|
+
- [Dashboard](https://clawtick.com/dashboard)
|
|
167
|
+
- [Documentation](https://clawtick.com/docs)
|
|
168
|
+
- [Issues](https://github.com/clawtick/cli/issues)
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT — see [LICENSE](./LICENSE)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clawtick Cloud API Client
|
|
3
|
+
*/
|
|
4
|
+
interface Config {
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
apiKey: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function loadConfig(): Config;
|
|
9
|
+
export declare function saveConfig(config: Partial<Config>): void;
|
|
10
|
+
export declare function getConfigPath(): string;
|
|
11
|
+
export declare class ApiClient {
|
|
12
|
+
private apiUrl;
|
|
13
|
+
private apiKey;
|
|
14
|
+
constructor();
|
|
15
|
+
isAuthenticated(): boolean;
|
|
16
|
+
private request;
|
|
17
|
+
listJobs(): Promise<any>;
|
|
18
|
+
createJob(data: {
|
|
19
|
+
name?: string;
|
|
20
|
+
cron: string;
|
|
21
|
+
message: string;
|
|
22
|
+
agent?: string;
|
|
23
|
+
channel?: string;
|
|
24
|
+
deliver?: boolean;
|
|
25
|
+
replyTo?: string;
|
|
26
|
+
timezone?: string;
|
|
27
|
+
}): Promise<any>;
|
|
28
|
+
deleteJob(jobId: string): Promise<any>;
|
|
29
|
+
updateJob(jobId: string, data: any): Promise<any>;
|
|
30
|
+
triggerJob(jobId: string): Promise<any>;
|
|
31
|
+
getStatus(): Promise<any>;
|
|
32
|
+
updateGateway(url: string, token: string): Promise<any>;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clawtick Cloud API Client
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
const CONFIG_DIR = join(homedir(), ".clawtick");
|
|
8
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
9
|
+
const DEFAULT_API_URL = "https://api.clawtick.com";
|
|
10
|
+
function ensureConfigDir() {
|
|
11
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
12
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function loadConfig() {
|
|
16
|
+
ensureConfigDir();
|
|
17
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
18
|
+
return { apiUrl: DEFAULT_API_URL, apiKey: "" };
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { apiUrl: DEFAULT_API_URL, apiKey: "" };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function saveConfig(config) {
|
|
28
|
+
ensureConfigDir();
|
|
29
|
+
const current = loadConfig();
|
|
30
|
+
const merged = { ...current, ...config };
|
|
31
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
|
|
32
|
+
}
|
|
33
|
+
export function getConfigPath() {
|
|
34
|
+
return CONFIG_FILE;
|
|
35
|
+
}
|
|
36
|
+
export class ApiClient {
|
|
37
|
+
apiUrl;
|
|
38
|
+
apiKey;
|
|
39
|
+
constructor() {
|
|
40
|
+
const config = loadConfig();
|
|
41
|
+
this.apiUrl = config.apiUrl;
|
|
42
|
+
this.apiKey = config.apiKey;
|
|
43
|
+
}
|
|
44
|
+
isAuthenticated() {
|
|
45
|
+
return !!this.apiKey;
|
|
46
|
+
}
|
|
47
|
+
async request(method, path, body) {
|
|
48
|
+
if (!this.apiKey) {
|
|
49
|
+
throw new Error("Not authenticated. Run: clawtick login");
|
|
50
|
+
}
|
|
51
|
+
const res = await fetch(`${this.apiUrl}${path}`, {
|
|
52
|
+
method,
|
|
53
|
+
headers: {
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
56
|
+
},
|
|
57
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
58
|
+
});
|
|
59
|
+
const data = await res.json().catch(() => ({}));
|
|
60
|
+
if (!res.ok) {
|
|
61
|
+
throw new Error(data.error || `API error: ${res.status}`);
|
|
62
|
+
}
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
// Jobs
|
|
66
|
+
async listJobs() {
|
|
67
|
+
return this.request("GET", "/v1/jobs");
|
|
68
|
+
}
|
|
69
|
+
async createJob(data) {
|
|
70
|
+
return this.request("POST", "/v1/jobs", data);
|
|
71
|
+
}
|
|
72
|
+
async deleteJob(jobId) {
|
|
73
|
+
return this.request("DELETE", `/v1/jobs/${jobId}`);
|
|
74
|
+
}
|
|
75
|
+
async updateJob(jobId, data) {
|
|
76
|
+
return this.request("PUT", `/v1/jobs/${jobId}`, data);
|
|
77
|
+
}
|
|
78
|
+
async triggerJob(jobId) {
|
|
79
|
+
return this.request("POST", `/v1/jobs/${jobId}/trigger`);
|
|
80
|
+
}
|
|
81
|
+
// Status
|
|
82
|
+
async getStatus() {
|
|
83
|
+
return this.request("GET", "/v1/status");
|
|
84
|
+
}
|
|
85
|
+
// Gateway
|
|
86
|
+
async updateGateway(url, token) {
|
|
87
|
+
return this.request("PUT", "/v1/gateway", { url, token });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Clawtick CLI — Cloud-powered scheduling for OpenClaw
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import ora from "ora";
|
|
8
|
+
import { ApiClient, saveConfig, loadConfig, getConfigPath } from "./api-client.js";
|
|
9
|
+
import { validateCronExpression, validateJobName, validateMessage, validateAgentId, } from "./validation.js";
|
|
10
|
+
const program = new Command();
|
|
11
|
+
const api = new ApiClient();
|
|
12
|
+
program
|
|
13
|
+
.name("clawtick")
|
|
14
|
+
.description("🦞 Cloud-powered scheduling for OpenClaw")
|
|
15
|
+
.version("2.0.0");
|
|
16
|
+
// ── Login ──────────────────────────────────────────────
|
|
17
|
+
program
|
|
18
|
+
.command("login")
|
|
19
|
+
.description("Authenticate with your Clawtick API key")
|
|
20
|
+
.option("--key <apiKey>", "API key (or set CLAWPULSE_API_KEY env var)")
|
|
21
|
+
.option("--api-url <url>", "API URL (for self-hosted)")
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
const apiKey = options.key || process.env.CLAWPULSE_API_KEY;
|
|
24
|
+
if (!apiKey) {
|
|
25
|
+
console.log(chalk.blue("🦞 Clawtick Login\n"));
|
|
26
|
+
console.log("Get your API key from the Clawtick dashboard:");
|
|
27
|
+
console.log(chalk.cyan(" https://clawtick.com/dashboard/api-keys\n"));
|
|
28
|
+
console.log("Then run:");
|
|
29
|
+
console.log(chalk.gray(" clawtick login --key cp_your_api_key_here"));
|
|
30
|
+
console.log(chalk.gray("\nOr set the environment variable:"));
|
|
31
|
+
console.log(chalk.gray(" export CLAWPULSE_API_KEY=cp_your_api_key_here"));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const spinner = ora("Authenticating...").start();
|
|
35
|
+
const config = { apiKey };
|
|
36
|
+
if (options.apiUrl)
|
|
37
|
+
config.apiUrl = options.apiUrl;
|
|
38
|
+
saveConfig(config);
|
|
39
|
+
spinner.succeed("Authenticated successfully");
|
|
40
|
+
console.log(chalk.gray(`Config saved to ${getConfigPath()}`));
|
|
41
|
+
});
|
|
42
|
+
// ── Logout ─────────────────────────────────────────────
|
|
43
|
+
program
|
|
44
|
+
.command("logout")
|
|
45
|
+
.description("Remove stored credentials")
|
|
46
|
+
.action(() => {
|
|
47
|
+
saveConfig({ apiKey: "" });
|
|
48
|
+
console.log(chalk.green("✅ Logged out"));
|
|
49
|
+
});
|
|
50
|
+
// ── Whoami ─────────────────────────────────────────────
|
|
51
|
+
program
|
|
52
|
+
.command("whoami")
|
|
53
|
+
.description("Show current authentication status")
|
|
54
|
+
.action(async () => {
|
|
55
|
+
const config = loadConfig();
|
|
56
|
+
if (!config.apiKey) {
|
|
57
|
+
console.log(chalk.yellow("Not authenticated. Run: clawtick login"));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.gray(`API URL: ${config.apiUrl}`));
|
|
61
|
+
console.log(chalk.gray(`API Key: ${config.apiKey.slice(0, 10)}...`));
|
|
62
|
+
const spinner = ora("Checking connection...").start();
|
|
63
|
+
try {
|
|
64
|
+
const status = await api.getStatus();
|
|
65
|
+
spinner.succeed(`Connected — Plan: ${status.plan}`);
|
|
66
|
+
console.log(chalk.gray(`Jobs: ${status.jobs.enabled}/${status.jobs.total}`));
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
spinner.fail(`API error: ${err.message}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// ── Gateway ────────────────────────────────────────────
|
|
74
|
+
const gateway = program.command("gateway").description("Manage OpenClaw gateway connection");
|
|
75
|
+
gateway
|
|
76
|
+
.command("set")
|
|
77
|
+
.description("Configure your OpenClaw gateway")
|
|
78
|
+
.requiredOption("--url <url>", "Gateway URL (e.g., https://your-vps.com)")
|
|
79
|
+
.requiredOption("--token <token>", "Gateway authentication token")
|
|
80
|
+
.action(async (options) => {
|
|
81
|
+
const spinner = ora("Configuring gateway...").start();
|
|
82
|
+
try {
|
|
83
|
+
await api.updateGateway(options.url, options.token);
|
|
84
|
+
spinner.succeed("Gateway configured");
|
|
85
|
+
console.log(chalk.gray(`URL: ${options.url}`));
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
spinner.fail(err.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
// ── Jobs ───────────────────────────────────────────────
|
|
93
|
+
const job = program.command("job").description("Manage scheduled jobs");
|
|
94
|
+
job
|
|
95
|
+
.command("list")
|
|
96
|
+
.description("List all scheduled jobs")
|
|
97
|
+
.action(async () => {
|
|
98
|
+
const spinner = ora("Fetching jobs...").start();
|
|
99
|
+
try {
|
|
100
|
+
const data = await api.listJobs();
|
|
101
|
+
const jobs = data.jobs || [];
|
|
102
|
+
if (jobs.length === 0) {
|
|
103
|
+
spinner.info("No jobs found. Create one with: clawtick job create");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
spinner.succeed(`${jobs.length} job(s) found\n`);
|
|
107
|
+
for (const j of jobs) {
|
|
108
|
+
const status = j.enabled ? chalk.green("●") : chalk.gray("○");
|
|
109
|
+
console.log(`${status} ${chalk.bold(j.name)} ${chalk.gray(`(${j.id})`)}`);
|
|
110
|
+
console.log(chalk.gray(` Cron: ${j.cron}`));
|
|
111
|
+
console.log(chalk.gray(` Message: ${j.message}`));
|
|
112
|
+
console.log(chalk.gray(` Agent: ${j.agent || "main"}`));
|
|
113
|
+
console.log(chalk.gray(` Runs: ${j.runCount} success, ${j.failCount} failed`));
|
|
114
|
+
if (j.lastRunAt) {
|
|
115
|
+
console.log(chalk.gray(` Last: ${new Date(j.lastRunAt).toLocaleString()}`));
|
|
116
|
+
}
|
|
117
|
+
console.log();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
spinner.fail(err.message);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
job
|
|
126
|
+
.command("create")
|
|
127
|
+
.description("Create a new scheduled job")
|
|
128
|
+
.requiredOption("--cron <expression>", 'Cron expression (e.g., "0 9 * * *")')
|
|
129
|
+
.requiredOption("--message <text>", "Message to send to the agent")
|
|
130
|
+
.option("--name <name>", "Job name")
|
|
131
|
+
.option("--agent <id>", "Agent ID (default: main)")
|
|
132
|
+
.option("--channel <channel>", "Target channel")
|
|
133
|
+
.option("--deliver", "Deliver agent response", false)
|
|
134
|
+
.option("--reply-to <target>", "Delivery target")
|
|
135
|
+
.option("--timezone <tz>", "Timezone (default: UTC)")
|
|
136
|
+
.action(async (options) => {
|
|
137
|
+
// Validate first (no spinner needed for local validation)
|
|
138
|
+
const cronCheck = validateCronExpression(options.cron);
|
|
139
|
+
if (!cronCheck.valid) {
|
|
140
|
+
console.error(chalk.red(`❌ ${cronCheck.error}`));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const msgCheck = validateMessage(options.message);
|
|
144
|
+
if (!msgCheck.valid) {
|
|
145
|
+
console.error(chalk.red(`❌ ${msgCheck.error}`));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
if (options.name) {
|
|
149
|
+
const nameCheck = validateJobName(options.name);
|
|
150
|
+
if (!nameCheck.valid) {
|
|
151
|
+
console.error(chalk.red(`❌ ${nameCheck.error}`));
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (options.agent) {
|
|
156
|
+
const agentCheck = validateAgentId(options.agent);
|
|
157
|
+
if (!agentCheck.valid) {
|
|
158
|
+
console.error(chalk.red(`❌ ${agentCheck.error}`));
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const spinner = ora("Creating job...").start();
|
|
163
|
+
try {
|
|
164
|
+
const data = await api.createJob({
|
|
165
|
+
name: options.name,
|
|
166
|
+
cron: options.cron,
|
|
167
|
+
message: options.message,
|
|
168
|
+
agent: options.agent,
|
|
169
|
+
channel: options.channel,
|
|
170
|
+
deliver: options.deliver,
|
|
171
|
+
replyTo: options.replyTo,
|
|
172
|
+
timezone: options.timezone,
|
|
173
|
+
});
|
|
174
|
+
const j = data.job;
|
|
175
|
+
spinner.succeed("Job created");
|
|
176
|
+
console.log(chalk.gray(`ID: ${j.id}`));
|
|
177
|
+
console.log(chalk.gray(`Name: ${j.name}`));
|
|
178
|
+
console.log(chalk.gray(`Cron: ${j.cron}`));
|
|
179
|
+
console.log(chalk.gray(`Message: ${j.message}`));
|
|
180
|
+
console.log(chalk.gray(`Agent: ${j.agent}`));
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
spinner.fail(err.message);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
job
|
|
188
|
+
.command("remove <jobId>")
|
|
189
|
+
.description("Delete a scheduled job")
|
|
190
|
+
.action(async (jobId) => {
|
|
191
|
+
const spinner = ora("Deleting job...").start();
|
|
192
|
+
try {
|
|
193
|
+
await api.deleteJob(jobId);
|
|
194
|
+
spinner.succeed(`Job deleted: ${jobId}`);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
spinner.fail(err.message);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
job
|
|
202
|
+
.command("update <jobId>")
|
|
203
|
+
.description("Update a job")
|
|
204
|
+
.option("--name <name>", "New name")
|
|
205
|
+
.option("--cron <expression>", "New cron expression")
|
|
206
|
+
.option("--message <text>", "New message")
|
|
207
|
+
.option("--enable", "Enable the job")
|
|
208
|
+
.option("--disable", "Disable the job")
|
|
209
|
+
.action(async (jobId, options) => {
|
|
210
|
+
const updates = {};
|
|
211
|
+
if (options.name)
|
|
212
|
+
updates.name = options.name;
|
|
213
|
+
if (options.cron)
|
|
214
|
+
updates.cron = options.cron;
|
|
215
|
+
if (options.message)
|
|
216
|
+
updates.message = options.message;
|
|
217
|
+
if (options.enable)
|
|
218
|
+
updates.enabled = true;
|
|
219
|
+
if (options.disable)
|
|
220
|
+
updates.enabled = false;
|
|
221
|
+
if (Object.keys(updates).length === 0) {
|
|
222
|
+
console.error(chalk.yellow("No updates provided. Use --help for options."));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const spinner = ora("Updating job...").start();
|
|
226
|
+
try {
|
|
227
|
+
await api.updateJob(jobId, updates);
|
|
228
|
+
spinner.succeed(`Job updated: ${jobId}`);
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
spinner.fail(err.message);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
job
|
|
236
|
+
.command("trigger <jobId>")
|
|
237
|
+
.description("Manually trigger a job now")
|
|
238
|
+
.action(async (jobId) => {
|
|
239
|
+
const spinner = ora("Triggering job...").start();
|
|
240
|
+
try {
|
|
241
|
+
await api.triggerJob(jobId);
|
|
242
|
+
spinner.succeed(`Job triggered: ${jobId}`);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
spinner.fail(err.message);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
job
|
|
250
|
+
.command("enable <jobId>")
|
|
251
|
+
.description("Enable (resume) a paused job")
|
|
252
|
+
.action(async (jobId) => {
|
|
253
|
+
const spinner = ora("Enabling job...").start();
|
|
254
|
+
try {
|
|
255
|
+
await api.updateJob(jobId, { enabled: true });
|
|
256
|
+
spinner.succeed(`Job enabled: ${jobId}`);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
spinner.fail(err.message);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
job
|
|
264
|
+
.command("disable <jobId>")
|
|
265
|
+
.description("Disable (pause) a job")
|
|
266
|
+
.action(async (jobId) => {
|
|
267
|
+
const spinner = ora("Disabling job...").start();
|
|
268
|
+
try {
|
|
269
|
+
await api.updateJob(jobId, { enabled: false });
|
|
270
|
+
spinner.succeed(`Job disabled: ${jobId}`);
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
spinner.fail(err.message);
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
// ── Status ─────────────────────────────────────────────
|
|
278
|
+
program
|
|
279
|
+
.command("status")
|
|
280
|
+
.description("Show account status and stats")
|
|
281
|
+
.action(async () => {
|
|
282
|
+
const spinner = ora("Fetching status...").start();
|
|
283
|
+
try {
|
|
284
|
+
const s = await api.getStatus();
|
|
285
|
+
spinner.succeed("Status loaded\n");
|
|
286
|
+
console.log(chalk.gray(`Plan: ${s.plan}`));
|
|
287
|
+
console.log(chalk.gray(`Jobs: ${s.jobs.enabled} enabled / ${s.jobs.total} total`));
|
|
288
|
+
console.log(chalk.gray(`Total runs: ${s.runs.total}`));
|
|
289
|
+
console.log(chalk.gray(`Success rate: ${s.runs.successRate}%`));
|
|
290
|
+
console.log(chalk.gray(`Last 24h: ${s.last24h.total} runs (${s.last24h.failed} failed)`));
|
|
291
|
+
console.log();
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
spinner.fail(err.message);
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
program.parse();
|
|
299
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clawtick — Cloud-powered scheduling for OpenClaw
|
|
3
|
+
*/
|
|
4
|
+
export { ApiClient, loadConfig, saveConfig } from "./api-client.js";
|
|
5
|
+
export { validateCronExpression, validateJobName, validateMessage, validateChannel, validateAgentId, } from "./validation.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EACH,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,GAClB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation utilities
|
|
3
|
+
*/
|
|
4
|
+
export declare class ValidationError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Validate cron expression (5-field standard format)
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateCronExpression(cron: string): {
|
|
11
|
+
valid: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Validate job name
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateJobName(name: string): {
|
|
18
|
+
valid: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Validate message
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateMessage(message: string): {
|
|
25
|
+
valid: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Validate channel name
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateChannel(channel: string): {
|
|
32
|
+
valid: boolean;
|
|
33
|
+
error?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Validate Telegram chat ID
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateTelegramChatId(chatId: string): {
|
|
39
|
+
valid: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Validate phone number (E.164 format)
|
|
44
|
+
*/
|
|
45
|
+
export declare function validatePhoneNumber(phone: string): {
|
|
46
|
+
valid: boolean;
|
|
47
|
+
error?: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Validate agent ID
|
|
51
|
+
*/
|
|
52
|
+
export declare function validateAgentId(agentId: string): {
|
|
53
|
+
valid: boolean;
|
|
54
|
+
error?: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Validate job ID format
|
|
58
|
+
*/
|
|
59
|
+
export declare function validateJobId(jobId: string): {
|
|
60
|
+
valid: boolean;
|
|
61
|
+
error?: string;
|
|
62
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input validation utilities
|
|
3
|
+
*/
|
|
4
|
+
export class ValidationError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ValidationError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Validate cron expression (5-field standard format)
|
|
12
|
+
*/
|
|
13
|
+
export function validateCronExpression(cron) {
|
|
14
|
+
if (!cron || typeof cron !== 'string') {
|
|
15
|
+
return { valid: false, error: 'Cron expression is required' };
|
|
16
|
+
}
|
|
17
|
+
const trimmed = cron.trim();
|
|
18
|
+
if (trimmed.length === 0) {
|
|
19
|
+
return { valid: false, error: 'Cron expression cannot be empty' };
|
|
20
|
+
}
|
|
21
|
+
const parts = trimmed.split(/\s+/);
|
|
22
|
+
if (parts.length < 5 || parts.length > 6) {
|
|
23
|
+
return {
|
|
24
|
+
valid: false,
|
|
25
|
+
error: `Invalid cron expression: expected 5 fields, got ${parts.length}\n\nExamples:\n */5 * * * * - Every 5 minutes\n 0 9 * * * - Every day at 9 AM\n 0 9 * * 1-5 - Every weekday at 9 AM\n\nUse https://crontab.guru to build expressions.`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// Basic field validation
|
|
29
|
+
const fieldPattern = /^(\*|[0-9]+(-[0-9]+)?(\/[0-9]+)?)(,(\*|[0-9]+(-[0-9]+)?(\/[0-9]+)?))*$/;
|
|
30
|
+
for (const part of parts) {
|
|
31
|
+
if (part !== '?' && !fieldPattern.test(part)) {
|
|
32
|
+
return {
|
|
33
|
+
valid: false,
|
|
34
|
+
error: `Invalid cron field: "${part}"\n\nUse https://crontab.guru to build expressions.`
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { valid: true };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validate job name
|
|
42
|
+
*/
|
|
43
|
+
export function validateJobName(name) {
|
|
44
|
+
if (!name || typeof name !== 'string') {
|
|
45
|
+
return { valid: false, error: 'Job name is required' };
|
|
46
|
+
}
|
|
47
|
+
const trimmed = name.trim();
|
|
48
|
+
if (trimmed.length === 0) {
|
|
49
|
+
return { valid: false, error: 'Job name cannot be empty' };
|
|
50
|
+
}
|
|
51
|
+
if (trimmed.length > 100) {
|
|
52
|
+
return { valid: false, error: 'Job name must be 100 characters or less' };
|
|
53
|
+
}
|
|
54
|
+
// Check for invalid characters
|
|
55
|
+
if (!/^[a-zA-Z0-9\s\-_]+$/.test(trimmed)) {
|
|
56
|
+
return { valid: false, error: 'Job name can only contain letters, numbers, spaces, hyphens, and underscores' };
|
|
57
|
+
}
|
|
58
|
+
return { valid: true };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate message
|
|
62
|
+
*/
|
|
63
|
+
export function validateMessage(message) {
|
|
64
|
+
if (!message || typeof message !== 'string') {
|
|
65
|
+
return { valid: false, error: 'Message is required' };
|
|
66
|
+
}
|
|
67
|
+
const trimmed = message.trim();
|
|
68
|
+
if (trimmed.length === 0) {
|
|
69
|
+
return { valid: false, error: 'Message cannot be empty' };
|
|
70
|
+
}
|
|
71
|
+
if (trimmed.length > 5000) {
|
|
72
|
+
return { valid: false, error: 'Message must be 5000 characters or less' };
|
|
73
|
+
}
|
|
74
|
+
return { valid: true };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate channel name
|
|
78
|
+
*/
|
|
79
|
+
export function validateChannel(channel) {
|
|
80
|
+
const validChannels = [
|
|
81
|
+
'whatsapp',
|
|
82
|
+
'telegram',
|
|
83
|
+
'slack',
|
|
84
|
+
'discord',
|
|
85
|
+
'signal',
|
|
86
|
+
'imessage',
|
|
87
|
+
'googlechat',
|
|
88
|
+
'mattermost',
|
|
89
|
+
'matrix',
|
|
90
|
+
'nostr',
|
|
91
|
+
'msteams',
|
|
92
|
+
'line',
|
|
93
|
+
'zalo',
|
|
94
|
+
'bluebubbles',
|
|
95
|
+
'nextcloud-talk'
|
|
96
|
+
];
|
|
97
|
+
const trimmed = channel.trim().toLowerCase();
|
|
98
|
+
if (!validChannels.includes(trimmed)) {
|
|
99
|
+
return {
|
|
100
|
+
valid: false,
|
|
101
|
+
error: `Invalid channel: ${channel}\n\nValid channels:\n ${validChannels.join(', ')}`
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return { valid: true };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Validate Telegram chat ID
|
|
108
|
+
*/
|
|
109
|
+
export function validateTelegramChatId(chatId) {
|
|
110
|
+
if (!chatId || typeof chatId !== 'string') {
|
|
111
|
+
return { valid: false, error: 'Telegram chat ID is required when using Telegram channel' };
|
|
112
|
+
}
|
|
113
|
+
// Telegram chat IDs are numeric (positive or negative)
|
|
114
|
+
if (!/^-?\d+$/.test(chatId.trim())) {
|
|
115
|
+
return {
|
|
116
|
+
valid: false,
|
|
117
|
+
error: 'Invalid Telegram chat ID format. Must be a number.\n\nGet your chat ID from @userinfobot on Telegram.'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return { valid: true };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Validate phone number (E.164 format)
|
|
124
|
+
*/
|
|
125
|
+
export function validatePhoneNumber(phone) {
|
|
126
|
+
if (!phone || typeof phone !== 'string') {
|
|
127
|
+
return { valid: false, error: 'Phone number is required' };
|
|
128
|
+
}
|
|
129
|
+
// E.164 format: +[country code][number] (e.g., +15555551234)
|
|
130
|
+
if (!/^\+[1-9]\d{1,14}$/.test(phone.trim())) {
|
|
131
|
+
return {
|
|
132
|
+
valid: false,
|
|
133
|
+
error: 'Invalid phone number format. Must be in E.164 format (e.g., +15555551234)'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return { valid: true };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Validate agent ID
|
|
140
|
+
*/
|
|
141
|
+
export function validateAgentId(agentId) {
|
|
142
|
+
if (!agentId || typeof agentId !== 'string') {
|
|
143
|
+
return { valid: false, error: 'Agent ID is required' };
|
|
144
|
+
}
|
|
145
|
+
const trimmed = agentId.trim();
|
|
146
|
+
if (trimmed.length === 0) {
|
|
147
|
+
return { valid: false, error: 'Agent ID cannot be empty' };
|
|
148
|
+
}
|
|
149
|
+
if (trimmed.length > 50) {
|
|
150
|
+
return { valid: false, error: 'Agent ID must be 50 characters or less' };
|
|
151
|
+
}
|
|
152
|
+
return { valid: true };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Validate job ID format
|
|
156
|
+
*/
|
|
157
|
+
export function validateJobId(jobId) {
|
|
158
|
+
if (!jobId || typeof jobId !== 'string') {
|
|
159
|
+
return { valid: false, error: 'Job ID is required' };
|
|
160
|
+
}
|
|
161
|
+
const trimmed = jobId.trim();
|
|
162
|
+
if (trimmed.length === 0) {
|
|
163
|
+
return { valid: false, error: 'Job ID cannot be empty' };
|
|
164
|
+
}
|
|
165
|
+
// Job IDs are in format: timestamp-randomstring
|
|
166
|
+
if (!/^\d+-[a-z0-9]+$/.test(trimmed)) {
|
|
167
|
+
return {
|
|
168
|
+
valid: false,
|
|
169
|
+
error: 'Invalid job ID format. Use "clawtick list" to see valid job IDs.'
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return { valid: true };
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawtick",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cloud-powered scheduling for OpenClaw — reliable cron, real-time monitoring, zero missed triggers",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"openclaw",
|
|
7
|
+
"cron",
|
|
8
|
+
"scheduler",
|
|
9
|
+
"automation",
|
|
10
|
+
"ai-agents",
|
|
11
|
+
"cloud"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Abdelhak Akermi",
|
|
15
|
+
"homepage": "https://clawtick.com/docs",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/Clawtick/cli.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/Clawtick/cli/issues"
|
|
22
|
+
},
|
|
23
|
+
"bin": {
|
|
24
|
+
"clawtick": "./dist/cli.js"
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"dev": "tsx src/cli.ts",
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"test": "vitest --run",
|
|
32
|
+
"start": "node dist/cli.js"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"chalk": "^5.6.0",
|
|
36
|
+
"commander": "^12.0.0",
|
|
37
|
+
"ora": "^8.2.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.0.0",
|
|
41
|
+
"tsx": "^4.0.0",
|
|
42
|
+
"typescript": "^5.6.0",
|
|
43
|
+
"vitest": "^4.0.0"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"README.md"
|
|
52
|
+
]
|
|
53
|
+
}
|