openjob 1.0.3

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.
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createServer = createServer;
37
+ const http = __importStar(require("http"));
38
+ const child_process_1 = require("child_process");
39
+ const state_1 = require("./state");
40
+ const registry_1 = require("./registry");
41
+ const executor_1 = require("./executor");
42
+ function json(res, status, body) {
43
+ res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8' });
44
+ res.end(JSON.stringify(body, null, 2));
45
+ }
46
+ function htmlPage(machineId) {
47
+ return `<!doctype html>
48
+ <html lang="zh-CN">
49
+ <head>
50
+ <meta charset="UTF-8" />
51
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
52
+ <title>jobs dashboard - ${machineId}</title>
53
+ <style>
54
+ :root { --bg:#0b1020; --panel:#131a2a; --muted:#93a4bf; --text:#eaf1ff; --ok:#22c55e; --warn:#f59e0b; --err:#ef4444; --line:#24304a; --accent:#60a5fa; }
55
+ * { box-sizing:border-box; }
56
+ body { margin:0; font-family:Inter,system-ui,sans-serif; background:linear-gradient(180deg,#0a0f1d,#0b1020); color:var(--text); }
57
+ .wrap { max-width:1200px; margin:0 auto; padding:24px; }
58
+ .hero { display:flex; justify-content:space-between; gap:16px; align-items:flex-start; margin-bottom:24px; }
59
+ .hero h1 { margin:0 0 8px; font-size:28px; }
60
+ .hero p { margin:0; color:var(--muted); }
61
+ .grid { display:grid; grid-template-columns:repeat(4,1fr); gap:16px; margin-bottom:24px; }
62
+ .card, .job { background:rgba(19,26,42,.92); border:1px solid var(--line); border-radius:16px; padding:18px; box-shadow:0 10px 30px rgba(0,0,0,.2); }
63
+ .metric { font-size:13px; color:var(--muted); }
64
+ .metric strong { display:block; margin-top:6px; font-size:28px; color:var(--text); }
65
+ .jobs { display:grid; gap:14px; }
66
+ .job-head { display:flex; justify-content:space-between; gap:16px; align-items:flex-start; }
67
+ .job h3 { margin:0 0 6px; font-size:18px; }
68
+ .desc { color:var(--muted); margin:0 0 12px; }
69
+ .meta { display:grid; grid-template-columns:repeat(4,1fr); gap:10px; margin:14px 0; }
70
+ .meta div { background:#0f1628; border:1px solid var(--line); border-radius:12px; padding:10px; }
71
+ .meta span { display:block; color:var(--muted); font-size:12px; margin-bottom:4px; }
72
+ .badge { display:inline-flex; padding:4px 10px; border-radius:999px; font-size:12px; border:1px solid var(--line); }
73
+ .success { color:var(--ok); }
74
+ .failed { color:var(--err); }
75
+ .running { color:var(--accent); }
76
+ .missed, .skipped { color:var(--warn); }
77
+ .idle { color:var(--muted); }
78
+ .actions { display:flex; gap:10px; margin-top:12px; flex-wrap:wrap; }
79
+ button { background:#13203a; color:var(--text); border:1px solid #27406b; border-radius:10px; padding:10px 14px; cursor:pointer; }
80
+ button:hover { border-color:var(--accent); }
81
+ pre { white-space:pre-wrap; background:#0b1220; border:1px solid var(--line); border-radius:12px; padding:12px; color:#cbd5e1; max-height:220px; overflow:auto; }
82
+ @media (max-width: 960px) { .grid, .meta { grid-template-columns:1fr 1fr; } }
83
+ @media (max-width: 640px) { .grid, .meta { grid-template-columns:1fr; } .hero { flex-direction:column; } }
84
+ </style>
85
+ </head>
86
+ <body>
87
+ <div class="wrap">
88
+ <div class="hero">
89
+ <div>
90
+ <h1>jobs dashboard</h1>
91
+ <p>查看本机任务状态、上次/下次执行时间、失败原因,以及 daemon 心跳。</p>
92
+ <p style="font-size:12px;color:var(--muted);margin-top:6px;" id="machineId">机器: ${machineId}</p>
93
+ </div>
94
+ <button onclick="loadAll()">刷新</button>
95
+ </div>
96
+ <div id="metrics" class="grid"></div>
97
+ <div id="jobs" class="jobs"></div>
98
+ </div>
99
+ <script>
100
+ async function api(path, options) {
101
+ const res = await fetch(path, options);
102
+ return res.json();
103
+ }
104
+ function esc(v) { return (v ?? '').toString().replace(/[&<>]/g, s => ({ '&':'&amp;','<':'&lt;','>':'&gt;' }[s])); }
105
+ function statusClass(status) { return ['success','failed','running','missed','skipped','idle'].includes(status) ? status : 'idle'; }
106
+ async function trigger(name, action) {
107
+ await api('/api/jobs/' + encodeURIComponent(name) + '/' + action, { method:'POST' });
108
+ await loadAll();
109
+ }
110
+ async function loadAll() {
111
+ const data = await api('/api/overview');
112
+ const metrics = document.getElementById('metrics');
113
+ metrics.innerHTML = (
114
+ '<div class="card metric">任务总数<strong>' + data.jobs.length + '</strong></div>' +
115
+ '<div class="card metric">已启用<strong>' + data.jobs.filter(j => j.enabled).length + '</strong></div>' +
116
+ '<div class="card metric">失败/错过<strong>' + data.jobs.filter(j => ['failed','missed'].includes(j.lastStatus)).length + '</strong></div>' +
117
+ '<div class="card metric">daemon<strong>' + esc(data.daemon.status || 'unknown') + '</strong></div>');
118
+
119
+ const machineEl = document.getElementById('machineId');
120
+ if (machineEl) machineEl.textContent = '机器: ' + esc(data.machineId || '-');
121
+
122
+ const jobsEl = document.getElementById('jobs');
123
+ jobsEl.innerHTML = data.jobs.map(job => (
124
+ '<section class="job">' +
125
+ '<div class="job-head">' +
126
+ '<div>' +
127
+ '<h3>' + esc(job.name) + '</h3>' +
128
+ '<p class="desc">' + esc(job.description) + '</p>' +
129
+ '</div>' +
130
+ '<span class="badge ' + statusClass(job.lastStatus) + '">' + esc(job.lastStatus || 'idle') + '</span>' +
131
+ '</div>' +
132
+ '<div class="meta">' +
133
+ '<div><span>cron</span>' + esc(job.cron) + '</div>' +
134
+ '<div><span>下次执行</span>' + esc(job.nextRun || '-') + '</div>' +
135
+ '<div><span>上次执行</span>' + esc(job.lastRun || '-') + '</div>' +
136
+ '<div><span>失败原因</span>' + esc(job.lastError || job.lastExitReason || '-') + '</div>' +
137
+ '</div>' +
138
+ '<div class="actions">' +
139
+ '<button onclick="trigger(\\'' + esc(job.name) + '\\',\\'run\\')">立即执行</button>' +
140
+ '<button onclick="trigger(\\'' + esc(job.name) + '\\',\\'' + (job.enabled ? 'disable' : 'enable') + '\\')">' + (job.enabled ? '禁用' : '启用') + '</button>' +
141
+ '</div>' +
142
+ '<pre>' + esc((job.history || []).slice(-3).map(item => '[' + item.status + '] ' + item.finishedAt + ' ' + (item.exitReason || '') + '\\n' + (item.stderr || item.stdout || '')).join('\\n\\n') || '暂无执行记录') + '</pre>' +
143
+ '</section>')).join('');
144
+ }
145
+ loadAll();
146
+ setInterval(loadAll, 15000);
147
+ </script>
148
+ </body>
149
+ </html>`;
150
+ }
151
+ function openBrowser(url) {
152
+ try {
153
+ (0, child_process_1.execFileSync)('/usr/bin/open', [url], { stdio: 'ignore' });
154
+ }
155
+ catch { }
156
+ }
157
+ function createServer(port = 0, autoOpen = true) {
158
+ (0, state_1.ensureRegistryState)();
159
+ const server = http.createServer(async (req, res) => {
160
+ const url = new URL(req.url || '/', 'http://127.0.0.1');
161
+ if (req.method === 'GET' && url.pathname === '/') {
162
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
163
+ res.end(htmlPage(state_1.MACHINE_ID));
164
+ return;
165
+ }
166
+ if (req.method === 'GET' && url.pathname === '/api/overview') {
167
+ const jobs = (0, state_1.summarizeJobs)().map((job) => ({
168
+ ...job,
169
+ history: (0, state_1.readRunLog)(job.name, 5)
170
+ }));
171
+ const response = {
172
+ daemon: (0, state_1.readDaemonState)(),
173
+ jobs,
174
+ machineId: state_1.MACHINE_ID
175
+ };
176
+ json(res, 200, response);
177
+ return;
178
+ }
179
+ const match = url.pathname.match(/\/api\/jobs\/([^/]+)\/(run|enable|disable)$/);
180
+ if (match && req.method === 'POST') {
181
+ const name = decodeURIComponent(match[1]);
182
+ const action = match[2];
183
+ try {
184
+ if (action === 'run') {
185
+ const job = (0, registry_1.getJob)(name);
186
+ if (!job)
187
+ return json(res, 404, { error: 'job_not_found' });
188
+ const result = await (0, executor_1.executeJob)(job, 'dashboard_manual');
189
+ return json(res, 200, result);
190
+ }
191
+ if (action === 'enable')
192
+ (0, registry_1.enableJob)(name);
193
+ if (action === 'disable')
194
+ (0, registry_1.disableJob)(name);
195
+ return json(res, 200, { ok: true });
196
+ }
197
+ catch (error) {
198
+ const errorMsg = error instanceof Error ? error.message : String(error);
199
+ return json(res, 500, { error: errorMsg });
200
+ }
201
+ }
202
+ json(res, 404, { error: 'not_found' });
203
+ });
204
+ server.listen(port, '127.0.0.1', () => {
205
+ const address = server.address();
206
+ if (address && typeof address !== 'string') {
207
+ const url = `http://127.0.0.1:${address.port}`;
208
+ if (autoOpen)
209
+ openBrowser(url);
210
+ process.stdout.write(`${url}\\n`);
211
+ }
212
+ });
213
+ return server;
214
+ }
215
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Job, JobRuntime, RunRecord, ShellResult, ConditionCheck, TriggerType } from './types';
2
+ export declare function extractCodeBlocks(markdown: string): string[];
3
+ export declare function resolveJobRuntime(job: Job): JobRuntime;
4
+ export declare function shouldSkipForCondition(job: Job): ConditionCheck | null;
5
+ export declare function runShell(command: string, cwd: string, timeoutMs: number): Promise<ShellResult>;
6
+ export declare function executeJob(job: Job, trigger?: TriggerType): Promise<RunRecord>;
7
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/F,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAG5D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU,CAatD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,GAAG,IAAI,CAsBtE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA6B9F;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAE,WAAsB,GAAG,OAAO,CAAC,SAAS,CAAC,CAuI9F"}
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.extractCodeBlocks = extractCodeBlocks;
37
+ exports.resolveJobRuntime = resolveJobRuntime;
38
+ exports.shouldSkipForCondition = shouldSkipForCondition;
39
+ exports.runShell = runShell;
40
+ exports.executeJob = executeJob;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const child_process_1 = require("child_process");
44
+ const parser_1 = require("./parser");
45
+ const state_1 = require("./state");
46
+ function extractCodeBlocks(markdown) {
47
+ const matches = [...markdown.matchAll(/```(?:bash|sh|shell)?\n([\s\S]*?)```/g)];
48
+ return matches.map(match => match[1].trim()).filter(Boolean);
49
+ }
50
+ function resolveJobRuntime(job) {
51
+ const jobSource = job.source;
52
+ const parsed = (0, parser_1.parseJob)(jobSource);
53
+ const cwd = job.cwd || parsed.cwd || path.dirname(jobSource);
54
+ const explicitCommand = job.command || parsed.command;
55
+ const commands = explicitCommand ? [explicitCommand] : extractCodeBlocks(fs.readFileSync(jobSource, 'utf8'));
56
+ return {
57
+ parsed,
58
+ cwd,
59
+ command: explicitCommand || commands.join('\n\n').trim(),
60
+ commandBlocks: commands
61
+ };
62
+ }
63
+ function shouldSkipForCondition(job) {
64
+ if (!job.condition)
65
+ return null;
66
+ const looksLikeScript = job.condition.startsWith('./') || job.condition.startsWith('/') || job.condition.endsWith('.sh');
67
+ if (!looksLikeScript) {
68
+ return {
69
+ skipped: true,
70
+ reason: 'condition_requires_ai_evaluation'
71
+ };
72
+ }
73
+ const resolved = path.isAbsolute(job.condition)
74
+ ? job.condition
75
+ : path.resolve(path.dirname(job.source), job.condition);
76
+ if (!fs.existsSync(resolved)) {
77
+ return {
78
+ skipped: true,
79
+ reason: `condition_script_not_found:${resolved}`
80
+ };
81
+ }
82
+ return { skipped: false, script: resolved };
83
+ }
84
+ function runShell(command, cwd, timeoutMs) {
85
+ return new Promise((resolve) => {
86
+ const child = (0, child_process_1.spawn)('/bin/zsh', ['-lc', command], {
87
+ cwd,
88
+ env: process.env,
89
+ stdio: ['ignore', 'pipe', 'pipe']
90
+ });
91
+ let stdout = '';
92
+ let stderr = '';
93
+ let finished = false;
94
+ let timedOut = false;
95
+ const timer = setTimeout(() => {
96
+ timedOut = true;
97
+ child.kill('SIGTERM');
98
+ setTimeout(() => child.kill('SIGKILL'), 1500);
99
+ }, timeoutMs);
100
+ child.stdout?.on('data', chunk => { stdout += String(chunk); });
101
+ child.stderr?.on('data', chunk => { stderr += String(chunk); });
102
+ child.on('close', (code, signal) => {
103
+ if (finished)
104
+ return;
105
+ finished = true;
106
+ clearTimeout(timer);
107
+ resolve({ code, signal, stdout, stderr, timedOut, pid: child.pid });
108
+ });
109
+ });
110
+ }
111
+ async function executeJob(job, trigger = 'manual') {
112
+ const runtime = resolveJobRuntime(job);
113
+ const startedAt = (0, state_1.nowIso)();
114
+ (0, state_1.updateJob)(job.name, current => ({
115
+ ...current,
116
+ lastRun: startedAt,
117
+ lastStartedAt: startedAt,
118
+ lastStatus: 'running',
119
+ lastError: null,
120
+ lastExitReason: null,
121
+ pid: process.pid
122
+ }));
123
+ const condition = shouldSkipForCondition(job);
124
+ if (condition?.skipped) {
125
+ const finishedAt = (0, state_1.nowIso)();
126
+ const record = {
127
+ jobName: job.name,
128
+ trigger,
129
+ startedAt,
130
+ finishedAt,
131
+ status: 'skipped',
132
+ exitReason: condition.reason || 'skipped',
133
+ stdout: '',
134
+ stderr: ''
135
+ };
136
+ (0, state_1.appendRunLog)(job.name, record);
137
+ const nextRun = (0, state_1.safeNextRun)(job.cron, new Date(finishedAt));
138
+ (0, state_1.updateJob)(job.name, current => ({
139
+ ...current,
140
+ lastFinishedAt: finishedAt,
141
+ lastStatus: 'skipped',
142
+ lastError: condition.reason || 'skipped',
143
+ lastExitReason: (condition.reason || 'skipped'),
144
+ nextRun,
145
+ pid: null,
146
+ history: [...(current.history || []), record].slice(-20)
147
+ }));
148
+ return record;
149
+ }
150
+ if (condition?.script) {
151
+ const check = await runShell(condition.script, runtime.cwd, 30_000);
152
+ if (check.code !== 0) {
153
+ const finishedAt = (0, state_1.nowIso)();
154
+ const record = {
155
+ jobName: job.name,
156
+ trigger,
157
+ startedAt,
158
+ finishedAt,
159
+ status: 'skipped',
160
+ exitReason: 'condition_not_met',
161
+ stdout: check.stdout,
162
+ stderr: check.stderr
163
+ };
164
+ (0, state_1.appendRunLog)(job.name, record);
165
+ const nextRun = (0, state_1.safeNextRun)(job.cron, new Date(finishedAt));
166
+ (0, state_1.updateJob)(job.name, current => ({
167
+ ...current,
168
+ lastFinishedAt: finishedAt,
169
+ lastStatus: 'skipped',
170
+ lastError: check.stderr.trim() || check.stdout.trim() || 'condition_not_met',
171
+ lastExitReason: 'condition_not_met',
172
+ nextRun,
173
+ pid: null,
174
+ history: [...(current.history || []), record].slice(-20)
175
+ }));
176
+ return record;
177
+ }
178
+ }
179
+ if (!runtime.command) {
180
+ const finishedAt = (0, state_1.nowIso)();
181
+ const record = {
182
+ jobName: job.name,
183
+ trigger,
184
+ startedAt,
185
+ finishedAt,
186
+ status: 'failed',
187
+ exitReason: 'no_executable_command',
188
+ stdout: '',
189
+ stderr: 'No `command` field and no bash/sh code block found in JOB.md'
190
+ };
191
+ (0, state_1.appendRunLog)(job.name, record);
192
+ const nextRun = (0, state_1.safeNextRun)(job.cron, new Date(finishedAt));
193
+ (0, state_1.updateJob)(job.name, current => ({
194
+ ...current,
195
+ lastFinishedAt: finishedAt,
196
+ lastFailureAt: finishedAt,
197
+ lastStatus: 'failed',
198
+ lastError: record.stderr,
199
+ lastExitReason: record.exitReason,
200
+ nextRun,
201
+ pid: null,
202
+ runCount: (current.runCount || 0) + 1,
203
+ consecutiveFailures: (current.consecutiveFailures || 0) + 1,
204
+ history: [...(current.history || []), record].slice(-20)
205
+ }));
206
+ return record;
207
+ }
208
+ const result = await runShell(runtime.command, runtime.cwd, (job.timeout || 60) * 60 * 1000);
209
+ const finishedAt = (0, state_1.nowIso)();
210
+ const success = !result.timedOut && result.code === 0;
211
+ const record = {
212
+ jobName: job.name,
213
+ trigger,
214
+ startedAt,
215
+ finishedAt,
216
+ status: success ? 'success' : 'failed',
217
+ exitReason: result.timedOut ? 'timeout' : (result.signal ? `signal:${result.signal}` : `exit:${result.code}`),
218
+ stdout: result.stdout,
219
+ stderr: result.stderr,
220
+ pid: result.pid
221
+ };
222
+ (0, state_1.appendRunLog)(job.name, record);
223
+ const nextRun = (0, state_1.safeNextRun)(job.cron, new Date(finishedAt));
224
+ (0, state_1.updateJob)(job.name, current => ({
225
+ ...current,
226
+ lastFinishedAt: finishedAt,
227
+ lastSuccessAt: success ? finishedAt : current.lastSuccessAt || null,
228
+ lastFailureAt: success ? current.lastFailureAt || null : finishedAt,
229
+ lastStatus: record.status,
230
+ lastError: success ? null : (record.stderr.trim() || record.stdout.trim() || record.exitReason),
231
+ lastExitReason: record.exitReason,
232
+ nextRun,
233
+ pid: null,
234
+ runCount: (current.runCount || 0) + 1,
235
+ consecutiveFailures: success ? 0 : (current.consecutiveFailures || 0) + 1,
236
+ history: [...(current.history || []), record].slice(-20)
237
+ }));
238
+ return record;
239
+ }
240
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { JobDefinition } from './types';
2
+ export declare function parseJob(filePath: string): JobDefinition;
3
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAiCxD"}
package/lib/parser.js ADDED
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.parseJob = parseJob;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const gray_matter_1 = __importDefault(require("gray-matter"));
43
+ const cron_parser_1 = require("cron-parser");
44
+ function parseJob(filePath) {
45
+ const abs = path.resolve(filePath);
46
+ const raw = fs.readFileSync(abs, 'utf8');
47
+ const { data, content } = (0, gray_matter_1.default)(raw);
48
+ // Validate required fields
49
+ if (!data.name)
50
+ throw new Error('Missing required field: name');
51
+ if (!data.cron)
52
+ throw new Error('Missing required field: cron');
53
+ if (!data.description)
54
+ throw new Error('Missing required field: description');
55
+ // Validate cron expression
56
+ try {
57
+ (0, cron_parser_1.parseExpression)(data.cron);
58
+ }
59
+ catch (e) {
60
+ const errorMsg = e instanceof Error ? e.message : String(e);
61
+ throw new Error(`Invalid cron expression "${data.cron}": ${errorMsg}`);
62
+ }
63
+ return {
64
+ name: data.name,
65
+ cron: data.cron,
66
+ description: data.description,
67
+ condition: data.condition || '',
68
+ allowedSkills: data.allowedSkills || [],
69
+ timeout: data.timeout || 60,
70
+ retry: data.retry || 0,
71
+ tags: data.tags || [],
72
+ command: data.command || '',
73
+ cwd: data.cwd || '',
74
+ body: content.trim(),
75
+ source: abs,
76
+ sourcePath: abs
77
+ };
78
+ }
79
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,4BAiCC;AAvCD,uCAAyB;AACzB,2CAA6B;AAC7B,8DAAiC;AACjC,6CAA8C;AAG9C,SAAgB,QAAQ,CAAC,QAAgB;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAA,qBAAM,EAAC,GAAG,CAAC,CAAC;IAEtC,2BAA2B;IAC3B,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAE9E,2BAA2B;IAC3B,IAAI,CAAC;QACH,IAAA,6BAAe,EAAC,IAAI,CAAC,IAAc,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,IAAI,MAAM,QAAQ,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAc;QACzB,IAAI,EAAE,IAAI,CAAC,IAAc;QACzB,WAAW,EAAE,IAAI,CAAC,WAAqB;QACvC,SAAS,EAAG,IAAI,CAAC,SAAoB,IAAI,EAAE;QAC3C,aAAa,EAAG,IAAI,CAAC,aAA0B,IAAI,EAAE;QACrD,OAAO,EAAG,IAAI,CAAC,OAAkB,IAAI,EAAE;QACvC,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,CAAC;QAClC,IAAI,EAAG,IAAI,CAAC,IAAiB,IAAI,EAAE;QACnC,OAAO,EAAG,IAAI,CAAC,OAAkB,IAAI,EAAE;QACvC,GAAG,EAAG,IAAI,CAAC,GAAc,IAAI,EAAE;QAC/B,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;QACpB,MAAM,EAAE,GAAG;QACX,UAAU,EAAE,GAAG;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Job } from './types';
2
+ export declare function generatePrompt(job: Partial<Job>): string;
3
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAE9B,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAUxD"}
package/lib/prompt.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generatePrompt = generatePrompt;
4
+ function generatePrompt(job) {
5
+ let prompt = `## Scheduled Job: ${job.name}\n\n${job.description}\n\n`;
6
+ prompt += `### Instructions\n\n`;
7
+ prompt += `Read and follow the instructions in \`${job.source}\`.\n\n`;
8
+ prompt += `- Respect the timeout: ${job.timeout ?? 60} minutes\n`;
9
+ prompt += `- Retry on failure: ${job.retry ?? 0} times\n`;
10
+ prompt += `- Allowed skills: ${job.allowedSkills?.length ? job.allowedSkills.join(', ') : 'all'}\n`;
11
+ prompt += `- Condition: ${job.condition || 'none'}\n\n`;
12
+ prompt += `Execute the job now.`;
13
+ return prompt;
14
+ }
15
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":";;AAEA,wCAUC;AAVD,SAAgB,cAAc,CAAC,GAAiB;IAC9C,IAAI,MAAM,GAAG,qBAAqB,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,WAAW,MAAM,CAAC;IACvE,MAAM,IAAI,sBAAsB,CAAC;IACjC,MAAM,IAAI,yCAAyC,GAAG,CAAC,MAAM,SAAS,CAAC;IACvE,MAAM,IAAI,0BAA0B,GAAG,CAAC,OAAO,IAAI,EAAE,YAAY,CAAC;IAClE,MAAM,IAAI,uBAAuB,GAAG,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC;IAC1D,MAAM,IAAI,qBAAqB,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACpG,MAAM,IAAI,gBAAgB,GAAG,CAAC,SAAS,IAAI,MAAM,MAAM,CAAC;IACxD,MAAM,IAAI,sBAAsB,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { Registry, Job } from './types';
2
+ export declare const AGENTS_DIR: string;
3
+ export declare const JOBS_DIR: string;
4
+ export declare const REGISTRY_PATH: string;
5
+ export declare function jobDir(name: string): string;
6
+ export declare function jobFile(name: string): string;
7
+ export declare function initRegistry(): Registry;
8
+ export declare function readRegistry(): Registry;
9
+ export declare function writeRegistry(registry: Registry): void;
10
+ export declare function addJob(job: Partial<Job> & {
11
+ name: string;
12
+ source: string;
13
+ sourcePath: string;
14
+ }): Job;
15
+ export declare function removeJob(name: string): void;
16
+ export declare function enableJob(name: string): void;
17
+ export declare function disableJob(name: string): void;
18
+ export declare function getJob(name: string): Job | undefined;
19
+ export declare function listJobs(): Job[];
20
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAExC,eAAO,MAAM,UAAU,QAA0D,CAAC;AAClF,eAAO,MAAM,QAAQ,QAAgC,CAAC;AACtD,eAAO,MAAM,aAAa,QAAqC,CAAC;AAEhE,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAQvC;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAGvC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAKtD;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAqDpG;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAK5C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM5C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM7C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAGpD;AAED,wBAAgB,QAAQ,IAAI,GAAG,EAAE,CAEhC"}