@orth/cli 0.2.19 → 0.2.21
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/dist/commands/auth.js +28 -7
- package/dist/commands/tasks.d.ts +15 -0
- package/dist/commands/tasks.js +227 -0
- package/dist/index.js +68 -0
- package/package.json +1 -1
package/dist/commands/auth.js
CHANGED
|
@@ -10,22 +10,31 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
10
10
|
const crypto_1 = __importDefault(require("crypto"));
|
|
11
11
|
const http_1 = __importDefault(require("http"));
|
|
12
12
|
const config_js_1 = require("../config.js");
|
|
13
|
-
const API_BASE = process.env.ORTH_API_URL || "https://api.orth.sh";
|
|
14
13
|
const WEB_BASE = process.env.ORTH_WEB_URL || "https://orthogonal.sh";
|
|
14
|
+
function escapeHtml(str) {
|
|
15
|
+
return str
|
|
16
|
+
.replace(/&/g, "&")
|
|
17
|
+
.replace(/</g, "<")
|
|
18
|
+
.replace(/>/g, ">")
|
|
19
|
+
.replace(/"/g, """)
|
|
20
|
+
.replace(/'/g, "'");
|
|
21
|
+
}
|
|
15
22
|
function openBrowser(url) {
|
|
16
|
-
|
|
23
|
+
// Use execFile-style args to avoid shell injection
|
|
24
|
+
const { execFile } = require("child_process");
|
|
17
25
|
const platform = process.platform;
|
|
18
26
|
if (platform === "darwin")
|
|
19
|
-
|
|
27
|
+
execFile("open", [url]);
|
|
20
28
|
else if (platform === "win32")
|
|
21
|
-
|
|
29
|
+
execFile("cmd", ["/c", "start", "", url]);
|
|
22
30
|
else
|
|
23
|
-
|
|
31
|
+
execFile("xdg-open", [url]);
|
|
24
32
|
}
|
|
25
33
|
async function browserLogin() {
|
|
26
34
|
// Generate a random state token to prevent CSRF
|
|
27
35
|
const state = crypto_1.default.randomBytes(32).toString("hex");
|
|
28
36
|
return new Promise((resolve, reject) => {
|
|
37
|
+
let timeoutHandle;
|
|
29
38
|
const server = http_1.default.createServer((req, res) => {
|
|
30
39
|
const url = new URL(req.url || "/", `http://localhost`);
|
|
31
40
|
if (url.pathname === "/callback") {
|
|
@@ -34,6 +43,7 @@ async function browserLogin() {
|
|
|
34
43
|
const returnedState = url.searchParams.get("state");
|
|
35
44
|
// Verify state token
|
|
36
45
|
if (returnedState !== state) {
|
|
46
|
+
clearTimeout(timeoutHandle);
|
|
37
47
|
res.writeHead(403, { "Content-Type": "text/html" });
|
|
38
48
|
res.end(`
|
|
39
49
|
<html>
|
|
@@ -51,6 +61,7 @@ async function browserLogin() {
|
|
|
51
61
|
return;
|
|
52
62
|
}
|
|
53
63
|
if (key) {
|
|
64
|
+
clearTimeout(timeoutHandle);
|
|
54
65
|
// Send a nice HTML response
|
|
55
66
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
56
67
|
res.end(`
|
|
@@ -63,6 +74,13 @@ async function browserLogin() {
|
|
|
63
74
|
</body>
|
|
64
75
|
</html>
|
|
65
76
|
`);
|
|
77
|
+
if (!key.startsWith("orth_")) {
|
|
78
|
+
console.log(chalk_1.default.red("\n✗ Invalid API key format received"));
|
|
79
|
+
server.close();
|
|
80
|
+
clearTimeout(timeoutHandle);
|
|
81
|
+
reject(new Error("Invalid key format"));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
66
84
|
(0, config_js_1.setApiKey)(key);
|
|
67
85
|
console.log(chalk_1.default.green("\n✓ Logged in successfully!"));
|
|
68
86
|
console.log(chalk_1.default.gray(` Key: ${key.slice(0, 15)}...${key.slice(-4)}`));
|
|
@@ -70,13 +88,15 @@ async function browserLogin() {
|
|
|
70
88
|
resolve();
|
|
71
89
|
}
|
|
72
90
|
else {
|
|
91
|
+
clearTimeout(timeoutHandle);
|
|
92
|
+
const safeError = escapeHtml(error || "Unknown error");
|
|
73
93
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
74
94
|
res.end(`
|
|
75
95
|
<html>
|
|
76
96
|
<body style="font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f0f0f0;">
|
|
77
97
|
<div style="text-align: center; background: white; padding: 48px; border-radius: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
|
|
78
98
|
<h1 style="font-size: 24px; margin: 0 0 8px; color: #e11d48;">Authentication Failed</h1>
|
|
79
|
-
<p style="color: #666; margin: 0;">${
|
|
99
|
+
<p style="color: #666; margin: 0;">${safeError}</p>
|
|
80
100
|
</div>
|
|
81
101
|
</body>
|
|
82
102
|
</html>
|
|
@@ -104,13 +124,14 @@ async function browserLogin() {
|
|
|
104
124
|
console.log(chalk_1.default.gray(`If it doesn't open, visit: ${authUrl}\n`));
|
|
105
125
|
openBrowser(authUrl);
|
|
106
126
|
// Timeout after 5 minutes
|
|
107
|
-
setTimeout(() => {
|
|
127
|
+
timeoutHandle = setTimeout(() => {
|
|
108
128
|
console.log(chalk_1.default.red("\n✗ Login timed out. Try again."));
|
|
109
129
|
server.close();
|
|
110
130
|
reject(new Error("Timed out"));
|
|
111
131
|
}, 5 * 60 * 1000);
|
|
112
132
|
});
|
|
113
133
|
server.on("error", (err) => {
|
|
134
|
+
clearTimeout(timeoutHandle);
|
|
114
135
|
reject(err);
|
|
115
136
|
});
|
|
116
137
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function tasksListCommand(): Promise<void>;
|
|
2
|
+
export declare function tasksCreateCommand(options: {
|
|
3
|
+
skill: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
schedule?: string;
|
|
6
|
+
input?: string[];
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
export declare function tasksShowCommand(taskId: string): Promise<void>;
|
|
9
|
+
export declare function tasksDeleteCommand(taskId: string): Promise<void>;
|
|
10
|
+
export declare function tasksPauseCommand(taskId: string): Promise<void>;
|
|
11
|
+
export declare function tasksResumeCommand(taskId: string): Promise<void>;
|
|
12
|
+
export declare function tasksTriggerCommand(taskId: string): Promise<void>;
|
|
13
|
+
export declare function tasksLogsCommand(taskId: string, options: {
|
|
14
|
+
limit?: string;
|
|
15
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.tasksListCommand = tasksListCommand;
|
|
7
|
+
exports.tasksCreateCommand = tasksCreateCommand;
|
|
8
|
+
exports.tasksShowCommand = tasksShowCommand;
|
|
9
|
+
exports.tasksDeleteCommand = tasksDeleteCommand;
|
|
10
|
+
exports.tasksPauseCommand = tasksPauseCommand;
|
|
11
|
+
exports.tasksResumeCommand = tasksResumeCommand;
|
|
12
|
+
exports.tasksTriggerCommand = tasksTriggerCommand;
|
|
13
|
+
exports.tasksLogsCommand = tasksLogsCommand;
|
|
14
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
15
|
+
const ora_1 = __importDefault(require("ora"));
|
|
16
|
+
const api_js_1 = require("../api.js");
|
|
17
|
+
// Common cron presets
|
|
18
|
+
const CRON_PRESETS = {
|
|
19
|
+
"every-5-min": "*/5 * * * *",
|
|
20
|
+
"every-hour": "0 * * * *",
|
|
21
|
+
"every-day-9am": "0 9 * * *",
|
|
22
|
+
"every-weekday-9am": "0 9 * * 1-5",
|
|
23
|
+
"every-monday": "0 9 * * 1",
|
|
24
|
+
"every-month": "0 9 1 * *",
|
|
25
|
+
};
|
|
26
|
+
function cronToHuman(expr) {
|
|
27
|
+
const presetName = Object.entries(CRON_PRESETS).find(([, v]) => v === expr)?.[0];
|
|
28
|
+
if (presetName) {
|
|
29
|
+
return presetName.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
30
|
+
}
|
|
31
|
+
return expr;
|
|
32
|
+
}
|
|
33
|
+
function formatTimeAgo(dateStr) {
|
|
34
|
+
const diff = Date.now() - new Date(dateStr).getTime();
|
|
35
|
+
const mins = Math.floor(diff / 60000);
|
|
36
|
+
if (mins < 1)
|
|
37
|
+
return "just now";
|
|
38
|
+
if (mins < 60)
|
|
39
|
+
return `${mins}m ago`;
|
|
40
|
+
const hours = Math.floor(mins / 60);
|
|
41
|
+
if (hours < 24)
|
|
42
|
+
return `${hours}h ago`;
|
|
43
|
+
const days = Math.floor(hours / 24);
|
|
44
|
+
return `${days}d ago`;
|
|
45
|
+
}
|
|
46
|
+
function statusBadge(status) {
|
|
47
|
+
switch (status) {
|
|
48
|
+
case "active": return chalk_1.default.green("● active");
|
|
49
|
+
case "paused": return chalk_1.default.yellow("● paused");
|
|
50
|
+
case "succeeded": return chalk_1.default.green("✓ succeeded");
|
|
51
|
+
case "failed": return chalk_1.default.red("✗ failed");
|
|
52
|
+
case "running": return chalk_1.default.blue("◌ running");
|
|
53
|
+
case "pending": return chalk_1.default.gray("○ pending");
|
|
54
|
+
default: return chalk_1.default.gray(status);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function tasksListCommand() {
|
|
58
|
+
const spinner = (0, ora_1.default)("Fetching tasks...").start();
|
|
59
|
+
try {
|
|
60
|
+
const data = await (0, api_js_1.apiRequest)("/tasks");
|
|
61
|
+
spinner.stop();
|
|
62
|
+
if (!data.tasks || data.tasks.length === 0) {
|
|
63
|
+
console.log(chalk_1.default.gray("\n No tasks yet. Create one with: orth tasks create\n"));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log(chalk_1.default.bold("\nTasks\n"));
|
|
67
|
+
for (const task of data.tasks) {
|
|
68
|
+
console.log(` ${chalk_1.default.white.bold(task.name)} ${statusBadge(task.status)} ${chalk_1.default.gray(cronToHuman(task.cron_expression))}`);
|
|
69
|
+
console.log(` Skill: ${chalk_1.default.cyan(task.skill_slug)} Runs: ${task.run_count}${task.last_run_at ? ` Last: ${formatTimeAgo(task.last_run_at)}` : ""}`);
|
|
70
|
+
console.log(` ID: ${chalk_1.default.gray(task.id)}`);
|
|
71
|
+
console.log();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
spinner.fail("Failed to fetch tasks");
|
|
76
|
+
console.error(chalk_1.default.red(err.message));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function tasksCreateCommand(options) {
|
|
81
|
+
const { skill, name, schedule } = options;
|
|
82
|
+
if (!skill) {
|
|
83
|
+
console.error(chalk_1.default.red("Skill slug is required. Usage: orth tasks create --skill <slug>"));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
// Parse schedule
|
|
87
|
+
let cronExpression = schedule || "0 9 * * *"; // default: daily at 9am
|
|
88
|
+
if (CRON_PRESETS[cronExpression]) {
|
|
89
|
+
cronExpression = CRON_PRESETS[cronExpression];
|
|
90
|
+
}
|
|
91
|
+
// Parse input key=value pairs
|
|
92
|
+
const skillInput = {};
|
|
93
|
+
if (options.input) {
|
|
94
|
+
for (const pair of options.input) {
|
|
95
|
+
const [key, ...rest] = pair.split("=");
|
|
96
|
+
if (key && rest.length > 0) {
|
|
97
|
+
skillInput[key] = rest.join("=");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const taskName = name || `${skill} (${cronToHuman(cronExpression)})`;
|
|
102
|
+
const spinner = (0, ora_1.default)("Creating task...").start();
|
|
103
|
+
try {
|
|
104
|
+
const data = await (0, api_js_1.apiRequest)("/tasks", {
|
|
105
|
+
method: "POST",
|
|
106
|
+
body: {
|
|
107
|
+
name: taskName,
|
|
108
|
+
skillSlug: skill,
|
|
109
|
+
skillInput,
|
|
110
|
+
cronExpression,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
spinner.succeed("Task created!");
|
|
114
|
+
console.log(`\n ${chalk_1.default.white.bold(data.task.name)}`);
|
|
115
|
+
console.log(` Skill: ${chalk_1.default.cyan(data.task.skill_slug)}`);
|
|
116
|
+
console.log(` Schedule: ${chalk_1.default.gray(cronToHuman(data.task.cron_expression))}`);
|
|
117
|
+
console.log(` Status: ${statusBadge(data.task.status)}`);
|
|
118
|
+
console.log(` ID: ${chalk_1.default.gray(data.task.id)}\n`);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
spinner.fail("Failed to create task");
|
|
122
|
+
console.error(chalk_1.default.red(err.message));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function tasksShowCommand(taskId) {
|
|
127
|
+
const spinner = (0, ora_1.default)("Fetching task...").start();
|
|
128
|
+
try {
|
|
129
|
+
const data = await (0, api_js_1.apiRequest)(`/tasks/${taskId}`);
|
|
130
|
+
spinner.stop();
|
|
131
|
+
const t = data.task;
|
|
132
|
+
console.log(`\n ${chalk_1.default.white.bold(t.name)}`);
|
|
133
|
+
console.log(` Status: ${statusBadge(t.status)}`);
|
|
134
|
+
console.log(` Skill: ${chalk_1.default.cyan(t.skill_slug)}`);
|
|
135
|
+
console.log(` Schedule: ${chalk_1.default.gray(cronToHuman(t.cron_expression))} (${t.timezone})`);
|
|
136
|
+
console.log(` Runs: ${t.run_count}${t.last_run_at ? ` Last: ${formatTimeAgo(t.last_run_at)}` : ""}`);
|
|
137
|
+
if (Object.keys(t.skill_input || {}).length > 0) {
|
|
138
|
+
console.log(` Input: ${chalk_1.default.gray(JSON.stringify(t.skill_input))}`);
|
|
139
|
+
}
|
|
140
|
+
console.log(` ID: ${chalk_1.default.gray(t.id)}`);
|
|
141
|
+
console.log(` Created: ${new Date(t.created_at).toLocaleString()}\n`);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
spinner.fail("Failed to fetch task");
|
|
145
|
+
console.error(chalk_1.default.red(err.message));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function tasksDeleteCommand(taskId) {
|
|
150
|
+
const spinner = (0, ora_1.default)("Deleting task...").start();
|
|
151
|
+
try {
|
|
152
|
+
await (0, api_js_1.apiRequest)(`/tasks/${taskId}`, { method: "DELETE" });
|
|
153
|
+
spinner.succeed("Task deleted");
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
spinner.fail("Failed to delete task");
|
|
157
|
+
console.error(chalk_1.default.red(err.message));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function tasksPauseCommand(taskId) {
|
|
162
|
+
const spinner = (0, ora_1.default)("Pausing task...").start();
|
|
163
|
+
try {
|
|
164
|
+
const data = await (0, api_js_1.apiRequest)(`/tasks/${taskId}/pause`, { method: "POST" });
|
|
165
|
+
spinner.succeed(`Task paused: ${data.task.name}`);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
spinner.fail("Failed to pause task");
|
|
169
|
+
console.error(chalk_1.default.red(err.message));
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function tasksResumeCommand(taskId) {
|
|
174
|
+
const spinner = (0, ora_1.default)("Resuming task...").start();
|
|
175
|
+
try {
|
|
176
|
+
const data = await (0, api_js_1.apiRequest)(`/tasks/${taskId}/resume`, { method: "POST" });
|
|
177
|
+
spinner.succeed(`Task resumed: ${data.task.name}`);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
spinner.fail("Failed to resume task");
|
|
181
|
+
console.error(chalk_1.default.red(err.message));
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function tasksTriggerCommand(taskId) {
|
|
186
|
+
const spinner = (0, ora_1.default)("Triggering task...").start();
|
|
187
|
+
try {
|
|
188
|
+
await (0, api_js_1.apiRequest)(`/tasks/${taskId}/trigger`, { method: "POST" });
|
|
189
|
+
spinner.succeed("Task triggered — check logs for progress");
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
spinner.fail("Failed to trigger task");
|
|
193
|
+
console.error(chalk_1.default.red(err.message));
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function tasksLogsCommand(taskId, options) {
|
|
198
|
+
const limit = parseInt(options.limit || "10") || 10;
|
|
199
|
+
const spinner = (0, ora_1.default)("Fetching run history...").start();
|
|
200
|
+
try {
|
|
201
|
+
const data = await (0, api_js_1.apiRequest)(`/tasks/${taskId}/runs?limit=${limit}`);
|
|
202
|
+
spinner.stop();
|
|
203
|
+
if (!data.runs || data.runs.length === 0) {
|
|
204
|
+
console.log(chalk_1.default.gray("\n No runs yet.\n"));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
console.log(chalk_1.default.bold(`\nRun History (${data.total} total)\n`));
|
|
208
|
+
for (const run of data.runs) {
|
|
209
|
+
const duration = run.duration_ms != null ? `${(run.duration_ms / 1000).toFixed(0)}s` : "—";
|
|
210
|
+
const time = run.started_at ? new Date(run.started_at).toLocaleString() : "—";
|
|
211
|
+
console.log(` ${statusBadge(run.status)} ${chalk_1.default.gray(time)} ${chalk_1.default.gray(duration)}`);
|
|
212
|
+
if (run.error) {
|
|
213
|
+
console.log(` ${chalk_1.default.red(run.error)}`);
|
|
214
|
+
}
|
|
215
|
+
if (run.output) {
|
|
216
|
+
const preview = run.output.slice(0, 200);
|
|
217
|
+
console.log(` ${chalk_1.default.gray(preview)}${run.output.length > 200 ? "..." : ""}`);
|
|
218
|
+
}
|
|
219
|
+
console.log();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
spinner.fail("Failed to fetch run history");
|
|
224
|
+
console.error(chalk_1.default.red(err.message));
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const account_js_1 = require("./commands/account.js");
|
|
|
10
10
|
const code_js_1 = require("./commands/code.js");
|
|
11
11
|
const skills_js_1 = require("./commands/skills.js");
|
|
12
12
|
const apiRequest_js_1 = require("./commands/apiRequest.js");
|
|
13
|
+
const tasks_js_1 = require("./commands/tasks.js");
|
|
13
14
|
const analytics_js_1 = require("./analytics.js");
|
|
14
15
|
/**
|
|
15
16
|
* Wraps an async action callback so that rejected promises are caught,
|
|
@@ -238,6 +239,73 @@ skillsGroup
|
|
|
238
239
|
await (0, skills_js_1.skillsRequestCommand)(input);
|
|
239
240
|
}));
|
|
240
241
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
242
|
+
// orth tasks <subcommand> — Scheduled task commands
|
|
243
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
244
|
+
const tasksGroup = program
|
|
245
|
+
.command("tasks")
|
|
246
|
+
.description("Scheduled task commands");
|
|
247
|
+
tasksGroup
|
|
248
|
+
.command("list")
|
|
249
|
+
.description("List your scheduled tasks")
|
|
250
|
+
.action(asyncAction(async () => {
|
|
251
|
+
(0, analytics_js_1.trackEvent)("tasks.list");
|
|
252
|
+
await (0, tasks_js_1.tasksListCommand)();
|
|
253
|
+
}));
|
|
254
|
+
tasksGroup
|
|
255
|
+
.command("create")
|
|
256
|
+
.description("Create a new scheduled task")
|
|
257
|
+
.requiredOption("-s, --skill <slug>", "Skill to run")
|
|
258
|
+
.option("-n, --name <name>", "Task name")
|
|
259
|
+
.option("--schedule <cron>", "Cron expression or preset (every-5-min, every-hour, every-day-9am, every-weekday-9am, every-monday, every-month)")
|
|
260
|
+
.option("-i, --input <pairs...>", "Skill input as key=value pairs")
|
|
261
|
+
.action(asyncAction(async (options) => {
|
|
262
|
+
(0, analytics_js_1.trackEvent)("tasks.create", { skill: options.skill });
|
|
263
|
+
await (0, tasks_js_1.tasksCreateCommand)(options);
|
|
264
|
+
}));
|
|
265
|
+
tasksGroup
|
|
266
|
+
.command("show <id>")
|
|
267
|
+
.description("Show task details")
|
|
268
|
+
.action(asyncAction(async (id) => {
|
|
269
|
+
(0, analytics_js_1.trackEvent)("tasks.show", { id });
|
|
270
|
+
await (0, tasks_js_1.tasksShowCommand)(id);
|
|
271
|
+
}));
|
|
272
|
+
tasksGroup
|
|
273
|
+
.command("delete <id>")
|
|
274
|
+
.description("Delete a scheduled task")
|
|
275
|
+
.action(asyncAction(async (id) => {
|
|
276
|
+
(0, analytics_js_1.trackEvent)("tasks.delete", { id });
|
|
277
|
+
await (0, tasks_js_1.tasksDeleteCommand)(id);
|
|
278
|
+
}));
|
|
279
|
+
tasksGroup
|
|
280
|
+
.command("pause <id>")
|
|
281
|
+
.description("Pause a scheduled task")
|
|
282
|
+
.action(asyncAction(async (id) => {
|
|
283
|
+
(0, analytics_js_1.trackEvent)("tasks.pause", { id });
|
|
284
|
+
await (0, tasks_js_1.tasksPauseCommand)(id);
|
|
285
|
+
}));
|
|
286
|
+
tasksGroup
|
|
287
|
+
.command("resume <id>")
|
|
288
|
+
.description("Resume a paused task")
|
|
289
|
+
.action(asyncAction(async (id) => {
|
|
290
|
+
(0, analytics_js_1.trackEvent)("tasks.resume", { id });
|
|
291
|
+
await (0, tasks_js_1.tasksResumeCommand)(id);
|
|
292
|
+
}));
|
|
293
|
+
tasksGroup
|
|
294
|
+
.command("trigger <id>")
|
|
295
|
+
.description("Manually trigger a task run")
|
|
296
|
+
.action(asyncAction(async (id) => {
|
|
297
|
+
(0, analytics_js_1.trackEvent)("tasks.trigger", { id });
|
|
298
|
+
await (0, tasks_js_1.tasksTriggerCommand)(id);
|
|
299
|
+
}));
|
|
300
|
+
tasksGroup
|
|
301
|
+
.command("logs <id>")
|
|
302
|
+
.description("View run history for a task")
|
|
303
|
+
.option("-l, --limit <number>", "Max results", "10")
|
|
304
|
+
.action(asyncAction(async (id, options) => {
|
|
305
|
+
(0, analytics_js_1.trackEvent)("tasks.logs", { id });
|
|
306
|
+
await (0, tasks_js_1.tasksLogsCommand)(id, options);
|
|
307
|
+
}));
|
|
308
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
241
309
|
// Backward-compatible aliases (flat commands)
|
|
242
310
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
243
311
|
program
|